AnyFormatKit icon indicating copy to clipboard operation
AnyFormatKit copied to clipboard

Filtering entered/pasted characters

Open ZsoltMolnarMBH opened this issue 2 years ago • 0 comments

Users can input any characters either by using a physical keyboard, or copy pasting into FormatTextField.

The issue is most prominent when the user is trying to paste something. Here is our example:

private struct AccountEditorView: View {
    @Binding var text: String
    let prompt: String
    let textColor: Color
    let cursorColor: Color

    var body: some View {
        FormatTextField(
            unformattedText: $text,
            placeholder: prompt,
            textPattern: "######## - ######## - ########"
        )
            .font(.body1)
            .keyboardType(.numberPad)
            .foregroundColor(textColor)
            .accentColor(cursorColor)
    }
}

user pastes: 12345678 - 12345678 - 12345678 FormatTextField shows: 12345678 - 12345678 - 12

Despite Tinamu's suggestion on a previous issue, this problem cannot be solved on SwiftUI view level, nor with using .onReceive modifier, nor with using a custom Binding implementation that filters the input, because these filtering closures run after the paste happened.

Suggested solution

FormatTextField should accept an optional CharacterSet as an init argument. If given, use this characterset to filter user input at the very first line of public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool

The following proof of concept solution seems to fix the problem:

        private let  allowedInput: CharacterSet = .decimalDigits
        
        public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            let string = String(string.unicodeScalars.filter { self.allowedInput.contains($0) })

ZsoltMolnarMBH avatar Mar 16 '22 17:03 ZsoltMolnarMBH