Search code examples
swiftuitextfield

How to set up UITextFieldDelegate for multiple text fields?


I can't run code like this, what's wrong? It doesn’t work for all textfield, but rather only one of them.

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    let newlenght1 = (textField1.text?.utf16.count)! + string.utf16.count - range.length // I have 3 textfield and I want for all of them same rule
    let newlenght2 = (textField2.text?.utf16.count)! + string.utf16.count - range.length // I have 3 textfield and I want for all of them same rule
    let newlenght3 = (textField3.text?.utf16.count)! + string.utf16.count - range.length // I have 3 textfield and I want for all of them same rule
    let allowedCharacters = "ABCDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ" // I only this charachters // allowed characters
    let characthers = CharacterSet(charactersIn: allowedCharacters)
    let charactersType = CharacterSet(charactersIn: string)
    let finalCharacters = characthers.isSuperset(of: charactersType)
    
    if textField == textField1 && textField == textField2 && textField == textField3 && newlenght1 <= 1 && newlenght2 <= 1 && newlenght3 <= 1 {
        return finalCharacters // but don't work for all textfield ,worked for only 1 textfield
    }else{
        return false
    }   
}

Solution

  • If your goal is to have all three text fields follow the same rule, set the delegate for all three. The shouldChangeCharactersIn only needs to check the “current” text field into which the user is currently typing.

    A minor observation, but I also would avoid recreating the CharacterSet of allowed characters repeatedly. You can simply make that a property.

    That reduces it down to something like:

    private let allowedCharacters = CharacterSet(charactersIn: "ABCDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ")
    
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if (textField.text?.count ?? 0) - range.length + string.count > 1 {
            return false
        }
    
        return allowedCharacters.isSuperset(of: CharacterSet(charactersIn: string.localizedUppercase))
    }
    

    If you want them only entering uppercase characters, I would:

    • Change the keyboard capitalization to “All Characters”, so they are more likely to not enter lowercase letters:

      enter image description here

    • Optionally change the capitalization by adding an “editing changed” action for your text field to:

      @IBAction func editingChanged(_ textField: UITextField) {
          textField.text = textField.text?.localizedUppercase
      }
      

      You might have to experiment whether you want to use localizedUppercase or uppercased() or uppercased(with:).

      Note, this “uppercase the whole string” logic is a little sloppy. If you were allowing multi-character strings in your input, you really would want to capture where the cursor was and restore it. (Otherwise it could be an annoying UX where if the user is changing the first character of a multi-character string, the cursor would jump to the end.) E.g., a simple rendition might be:

      @IBAction func editingChanged(_ textField: UITextField) {
          let range = textField.selectedTextRange
          textField.text = textField.text?.localizedUppercase
          textField.selectedTextRange = range
      }
      

      But for your single character input, the simpler example, above, should be sufficient.