Wednesday, June 7, 2023
HomeiOS Developmentios - SwiftUI Formatting TextField for bank card enter "xxxx-xxxx-xxxx-xxxx"

ios – SwiftUI Formatting TextField for bank card enter “xxxx-xxxx-xxxx-xxxx”


I wish to write a customized TextField on SwiftUI to have an enter with bank card format like this “xxxx-xxxx-xxxx-xxxx”, I used to be this solutions https://stackoverflow.com/a/48252437, however I am fighting UIViewRepresentable, once I wish to previous the numbers into the unique textual content, it would not appears to replace it with the format.

The textField will present you 12345, however I would like 1234 5

struct ContentView: View {
    
    @State var cardNumber: String = "12345" // <-- It will not be formatted till I sort one other one quantity
    
    var physique: some View {
        VStack {
            CreditCardTextField(quantity: $cardNumber)
                .body(top: 50)
                .border(.black)
        }
        .padding()
    }
}

And UIViewRepresentable the place I transported the code from the hyperlink reply

struct CreditCardTextField: UIViewRepresentable {
    @Binding public var quantity: String
    
    public init(quantity: Binding<String>) {
        self._number = quantity
    }
    
    public func makeUIView(context: Context) -> UITextField {
        let view = UITextField()
        view.addTarget(context.coordinator, motion: #selector(Coordinator.reformatAsCardNumber), for: .editingChanged)
        view.delegate = context.coordinator
        
        return view
    }
    
    public func updateUIView(_ uiView: UITextField, context: Context) {
        uiView.textual content = quantity // <-- I consider in right here I ought to replace the code in order that it is going to be formatted, however I can not get tips on how to refactore the code
    }
    
    public func makeCoordinator() -> Coordinator {
        Coordinator($quantity)
    }
    
    // MARK: Coordinator
    public class Coordinator: NSObject, UITextFieldDelegate {
        @Binding var quantity: String
        non-public var previousTextFieldContent: String?
        non-public var previousSelection: UITextRange?
        
        init(_ quantity: Binding<String>) {
            self._number = quantity
        }
        
        func textField(_ textField: UITextField, shouldChangeCharactersIn vary: NSRange, replacementString string: String) -> Bool {
            previousTextFieldContent = textField.textual content
            previousSelection = textField.selectedTextRange
            return true
        }
        
        @objc func reformatAsCardNumber(textField: UITextField, for occasion: UIControl.Occasion) {
            var targetCursorPosition = 0
            if let startPosition = textField.selectedTextRange?.begin {
                targetCursorPosition = textField.offset(from: textField.beginningOfDocument, to: startPosition)
            }
            
            var cardNumberWithoutSpaces = ""
            if let textual content = textField.textual content {
                cardNumberWithoutSpaces = self.removeNonDigits(string: textual content, andPreserveCursorPosition: &targetCursorPosition)
            }
            
            if cardNumberWithoutSpaces.rely > 16 {
                textField.textual content = previousTextFieldContent
                textField.selectedTextRange = previousSelection
                return
            }
            
            let cardNumberWithSpaces = self.insertCreditCardSpaces(cardNumberWithoutSpaces, preserveCursorPosition: &targetCursorPosition)

            textField.textual content = cardNumberWithSpaces
            quantity = cardNumberWithSpaces
            
            if let targetPosition = textField.place(from: textField.beginningOfDocument, offset: targetCursorPosition) {
                textField.selectedTextRange = textField.textRange(from: targetPosition, to: targetPosition)
            }
        }
        
        func removeNonDigits(string: String, andPreserveCursorPosition cursorPosition: inout Int) -> String {
            var digitsOnlyString = ""
            let originalCursorPosition = cursorPosition
            
            for i in Swift.stride(from: 0, to: string.rely, by: 1) {
                let characterToAdd = string[string.index(string.startIndex, offsetBy: i)]
                if characterToAdd >= "0" && characterToAdd <= "9" {
                    digitsOnlyString.append(characterToAdd)
                } else if i < originalCursorPosition {
                    cursorPosition -= 1
                }
            }
            
            return digitsOnlyString
        }
        
        func insertCreditCardSpaces(_ string: String, preserveCursorPosition cursorPosition: inout Int) -> String {
            var stringWithAddedSpaces = ""
            let cursorPositionInSpacelessString = cursorPosition
            
            for i in 0..<string.rely {
                if i > 0 && (i % 4) == 0 {
                    stringWithAddedSpaces.append(" ")
                    
                    if i < cursorPositionInSpacelessString {
                        cursorPosition += 1
                    }
                }
                
                let characterToAdd = string[
                    string.index(string.startIndex, offsetBy: i)
                ]
                stringWithAddedSpaces.append(characterToAdd)
            }
            
            return stringWithAddedSpaces
        }
    }
}



Supply hyperlink

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments