Skip to content

Instantly share code, notes, and snippets.

@amrit42087
Created June 11, 2020 13:01
Show Gist options
  • Save amrit42087/98750b2e22b299368b07ed6e78d530a8 to your computer and use it in GitHub Desktop.
Save amrit42087/98750b2e22b299368b07ed6e78d530a8 to your computer and use it in GitHub Desktop.
//
// BottomSheet.swift
// Squirrel-SwiftUI
//
// Created by Amritpal Singh on 24/05/20.
// Copyright © 2020 sidhu.com. All rights reserved.
//
import SwiftUI
class TextFieldFormatter: ObservableObject {
enum Formatter {
case expiry
case cardNumber
case non // No formatter is required
}
@Published var text = "" {
didSet {
if oldValue != text {
if text.count > characterLimit && oldValue.count <= characterLimit {
text = oldValue
} else {
text = formattedText()
}
}
}
}
let characterLimit: Int
let formaterType: Formatter
init(limit: Int = 5, type: Formatter = .non){
characterLimit = limit
formaterType = type
}
func formattedText() -> String {
switch formaterType {
case .expiry:
return formattedExpiry()
case .cardNumber:
return formattedCardNumber()
case .non:
return text
}
}
func formattedExpiry() -> String {
let allDigits = self.text.digits
var formattedText = ""
if allDigits.count == 1 {
formattedText = "\(allDigits[0])"
} else if allDigits.count == 2 {
if let number = Int("\(allDigits[0])\(allDigits[1])"),
number <= 12 {
formattedText = "\(allDigits[0])\(allDigits[1])"
} else {
formattedText = "\(allDigits[0])"
}
} else if allDigits.count == 3 {
formattedText = "\(allDigits[0])\(allDigits[1])/\(allDigits[2])"
} else if allDigits.count >= 4 {
formattedText = "\(allDigits[0])\(allDigits[1])/\(allDigits[2])\((allDigits[3]))"
}
return formattedText
}
func formattedCardNumber() -> String {
let trimmedString = text.components(separatedBy: .whitespaces).joined()
let arrOfCharacters = Array(trimmedString)
var modifiedCreditCardString = ""
if(arrOfCharacters.count > 0) {
for i in 0...arrOfCharacters.count-1 {
modifiedCreditCardString.append(arrOfCharacters[i])
if((i+1) % 4 == 0 && i+1 != arrOfCharacters.count) {
modifiedCreditCardString.append(" ")
}
}
}
return modifiedCreditCardString
}
}
extension String {
var digits: [Int] {
var result = [Int]()
for char in self {
if let number = Int(String(char)) {
result.append(number)
}
}
return result
}
func widthWithConstrainedHeight(height: CGFloat, font: UIFont = UIFont(name: "Avenir-normal", size: 14) ?? .systemFont(ofSize: 14)) -> CGFloat {
let constraintRect = CGSize(width: CGFloat.greatestFiniteMagnitude, height: height)
let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin,
attributes: [NSAttributedString.Key.font: font], context: nil)
return boundingBox.width
}
}
struct CustomTextField: UIViewRepresentable {
class Coordinator: NSObject, UITextFieldDelegate {
@Binding var text: String
var didBecomeFirstResponder = false
var textChanged: ((_ text: String?) -> Void)?
var textColor: UIColor = UIColor.black
var didTapReturnButton: (() -> Void)? = nil
init(text: Binding<String>,
textColor: UIColor?,
didChangeText: ((_ text: String?) -> Void)?,
didTapReturnButton: (() -> Void)?) {
_text = text
self.textColor = textColor ?? .black
textChanged = didChangeText
self.didTapReturnButton = didTapReturnButton
}
@objc func didChangeText(_ textField: UITextField) {
DispatchQueue.main.async {
self.text = textField.text ?? ""
}
print("Text changed")
textChanged?(text)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
didTapReturnButton?()
return true
}
}
@Binding var text: String
@Binding var isFirstResponder: Bool
var placeholder: String = "Search"
var font: UIFont? = UIFont(name: "Avenir-normal", size: 17)
var placeholderFont: UIFont? = nil
var textColor: UIColor = UIColor.black
var keyboardType: UIKeyboardType = .numberPad
var returnType: UIReturnKeyType = .default
var textChanged: ((_ text: String?) -> Void)? = nil
var didTapReturnButton: (() -> Void)? = nil
func makeUIView(context: UIViewRepresentableContext<CustomTextField>) -> UITextField {
let textField = UITextField(frame: .zero)
textField.addTarget(context.coordinator, action: #selector(context.coordinator.didChangeText(_:)), for: .editingChanged)
textField.tintColor = textColor
textField.textColor = textColor
textField.keyboardType = keyboardType
textField.returnKeyType = returnType
textField.delegate = context.coordinator
textField.placeholder = placeholder
textField.clearButtonMode = .whileEditing
textField.font = font
if let font = placeholderFont {
let attributes = [
NSAttributedString.Key.font : font
]
textField.attributedPlaceholder = NSAttributedString(string: placeholder, attributes:attributes)
}
return textField
}
func makeCoordinator() -> CustomTextField.Coordinator {
return Coordinator(text: $text,
textColor: textColor,
didChangeText: textChanged,
didTapReturnButton: didTapReturnButton)
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomTextField>) {
uiView.text = text
if isFirstResponder && !context.coordinator.didBecomeFirstResponder {
uiView.becomeFirstResponder()
context.coordinator.didBecomeFirstResponder = true
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment