// // TextField.swift // VDS // // Created by Matt Bruce on 5/1/24. // import Foundation import UIKit @objc(VDSTextField) open class TextField: UITextField { //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- required public init() { super.init(frame: .zero) initialSetup() } public override init(frame: CGRect) { super.init(frame: .zero) initialSetup() } public required init?(coder: NSCoder) { super.init(coder: coder) initialSetup() } var horizontalPadding: CGFloat = 0 open override func textRect(forBounds bounds: CGRect) -> CGRect { let rect = super.textRect(forBounds: bounds) return rect.insetBy(dx: -horizontalPadding, dy: 0) } open override func editingRect(forBounds bounds: CGRect) -> CGRect { let rect = super.editingRect(forBounds: bounds) return rect.insetBy(dx: -horizontalPadding, dy: 0) } open override func placeholderRect(forBounds bounds: CGRect) -> CGRect { let rect = super.placeholderRect(forBounds: bounds) return rect.insetBy(dx: -horizontalPadding, dy: 0) } open override var isSecureTextEntry: Bool { didSet { if isFirstResponder { _ = becomeFirstResponder() } } } open func initialSetup() { let accessView = UIView(frame: .init(origin: .zero, size: .init(width: UIScreen.main.bounds.width, height: 44))) accessView.backgroundColor = .white accessView.addBorder(side: .top, width: 1, color: .lightGray) let done = UIButton(type: .system) done.setTitle("Done", for: .normal) done.translatesAutoresizingMaskIntoConstraints = false done.addTarget(self, action: #selector(doneButtonAction), for: .touchUpInside) accessView.addSubview(done) done.pinCenterY() .pinTrailing(16) inputAccessoryView = accessView } @objc func doneButtonAction() { // Resigns the first responder status when 'Done' is tapped resignFirstResponder() } open override func becomeFirstResponder() -> Bool { let success = super.becomeFirstResponder() if isSecureTextEntry, let text { self.text?.removeAll() insertText(text) } return success } } extension UITextField { public func cursorPosition(range: NSRange, replacementString string: String, rawNumber: String, formattedNumber: String) -> UITextPosition? { let start = range.location let length = string.count let newCursorLocation = start + length // Adjust the cursor position to skip over formatting characters var formattedCharacterCount = 0 for (index, character) in formattedNumber.enumerated() { if index >= newCursorLocation + formattedCharacterCount { break } if !character.isNumber { formattedCharacterCount += 1 } } let finalCursorLocation = min(newCursorLocation + formattedCharacterCount, formattedNumber.count) return position(from: beginningOfDocument, offset: finalCursorLocation) } }