Hussam Eddin Hussam Eddin - 4 months ago 23
Swift Question

Change UITextField responder on Max Length

I have login controller where it has two textFields:


  • Access Card

  • Password



The Max Length for the access card is 9 and once the user type the ninth number, it should appear on the access card filed then the cursor needs to move to the password field.

In my code, the cursor is moving when the user clicks to enter the ninth number but the number doesn't appear and the cursor moves to the password field.

For example: I want to enter "123456789" as access card. Once I click "9" it doesn't appear but the cursor moves to password field:

LoginController.swift:

let ACCESSCARD_MAXLENGTH = 9
let PASSWORD_MAXLENGTH = 12
var AccessCardtextFieldLength = 0
var PasswordTextFieldLength = 0

class LoginViewController: UIViewController , UITextFieldDelegate {
@IBOutlet weak var AccessCardTextField: UITextField!

@IBOutlet weak var PasswordTextField: UITextField!

override func viewDidLoad() {
super.viewDidLoad()

// calling the function that initialize textFields
initializeTextFields()

}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()

}

// function is used to initialize textFields
func initializeTextFields () {

// To set the focus on the access card once the view load.
AccessCardTextField.becomeFirstResponder()


// This must be defined so we can apply the text field functions on it
AccessCardTextField.delegate = self
PasswordTextField.delegate = self


// Define the keyboard type of the textFields.
AccessCardTextField.keyboardType = UIKeyboardType.NumberPad
PasswordTextField.keyboardType = UIKeyboardType.ASCIICapable

}


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


AccessCardtextFieldLength = (textField.text?.characters.count)! + string.characters.count
PasswordTextFieldLength = (textField.text?.characters.count)! + string.characters.count
if (textField == AccessCardTextField){
for i in 0..<ACCESSCARD_MAXLENGTH{
if (AccessCardtextFieldLength == ACCESSCARD_MAXLENGTH){
PasswordTextField.becomeFirstResponder()
}
else{
return true
}
return false
}

}
if (textField == PasswordTextField){
return PasswordTextFieldLength <= PASSWORD_MAXLENGTH ? true : false

}

return true
}
}

Answer

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool will only update when it return true. In this case you are changing the firstResponder therefore it is not updated.

My suggestion is to use add target for this case. This is what you can do:

override func viewDidLoad() {
    super.viewDidLoad()

   // calling the function that initialize textFields
   initializeTextFields()
   accessCardTextField.addTarget(self, action: #selector(LoginViewController.accessCardTextFieldChanged(_:)), forControlEvents: .EditingChanged)
}

func accessCardTextFieldChanged(textField: UITextField) {
    if textField.text?.characters.count == ACCESSCARD_MAXLENGTH {
        modelTextField.becomeFirstResponder()
    }
}

This way, it save you quite a few line of code. Most importantly, only accessCardTextField changed will be call. You could do another function to check your password textfield length separately. Also, i renamed from AccessCardTextField to accessCardTextField. It is recommended to have variable starting with lower case.

Comments