Allowing single digit in UITextField in iOS

Use this code if you don't want to work with tag and it works better then above

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        // On inputing value to textfield
        if ((textField.text?.characters.count)! < 1  && string.characters.count > 0){
            if(textField == txtOne)
            {
                txtTwo.becomeFirstResponder()
            }
            if(textField == txtTwo)
            {
                txtThree.becomeFirstResponder()
            }
            if(textField == txtThree)
            {
                txtFour.becomeFirstResponder()
            }

            textField.text = string
            return false
        }
        else if ((textField.text?.characters.count)! >= 1  && string.characters.count == 0){
            // on deleting value from Textfield
            if(textField == txtTwo)
            {
                txtOne.becomeFirstResponder()
            }
            if(textField == txtThree)
            {
                txtTwo.becomeFirstResponder()
            }
            if(textField == txtFour)
            {
                txtThree.becomeFirstResponder()
            }
            textField.text = ""
            return false
        }
        else if ((textField.text?.characters.count)! >= 1  )
        {
            textField.text = string
            return false
        }
        return true
    }

Swift 4

Inspired by @Anurag Soni and @Varun Naharia answers

Variant A

extension EnterConfirmationCodeTextField: UITextFieldDelegate {

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        guard let textFieldCount = textField.text?.count else { return false }

        // Сlosure
        let setValueAndMoveForward = {
            textField.text = string
            let nextTag = textField.tag + 1
            if let nextResponder = textField.superview?.viewWithTag(nextTag) {
                nextResponder.becomeFirstResponder()
            }
        }

        // Сlosure
        let clearValueAndMoveBack = {
            textField.text = ""
            let previousTag = textField.tag - 1
            if let previousResponder = textField.superview?.viewWithTag(previousTag) {
                previousResponder.becomeFirstResponder()
            }
        }

        if textFieldCount < 1 && string.count > 0 {

            setValueAndMoveForward()

            if textField.tag == 4 {
                print("Do something")
            }

            return false

        } else if textFieldCount >= 1 && string.count == 0 {

            clearValueAndMoveBack()
            return false

        } else if textFieldCount >= 1 && string.count > 0 {

            let nextTag = self.tag + 1
            if let previousResponder = self.superview?.viewWithTag(nextTag) {
                previousResponder.becomeFirstResponder()

                if let activeTextField = previousResponder as? UITextField {
                    activeTextField.text = string
                }
            }

            return false
        }

        return true

    }

}

Variant B (a little bit another behavior):

extension EnterConfirmationCodeTextField: UITextFieldDelegate {

        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            guard let textFieldCount = textField.text?.count else { return false }

            // Сlosure
            let setValueAndMoveForward = {
                textField.text = string
                let nextTag = textField.tag + 1
                if let nextResponder = textField.superview?.viewWithTag(nextTag) {
                    nextResponder.becomeFirstResponder()
                }
            }

            // Сlosure
            let clearValueAndMoveBack = {
                textField.text = ""
                let previousTag = textField.tag - 1
                if let previousResponder = textField.superview?.viewWithTag(previousTag) {
                    previousResponder.becomeFirstResponder()
                }
            }

            if textFieldCount < 1 && string.count > 0 {

                setValueAndMoveForward()

                if textField.tag == 4 {
                    print("Do something")
                }

                return false

            } else if textFieldCount >= 1 && string.count == 0 {

                clearValueAndMoveBack()
                return false

            } else if textFieldCount >= 1 {

                setValueAndMoveForward()
                return false
            }

            return true

        }

 }

Also, I implemented this feature:

enter image description here

In the case where the last textFiled is empty, I just want to switch to the previous textFiled. I tried all this methods. But as for me the method below more elegant and works like a charm:

Variant A

class EnterConfirmationCodeTextField: UITextField {

    // MARK: Life cycle

    override func awakeFromNib() {
        super.awakeFromNib()

        delegate = self
    }

    // MARK: Methods

    override func deleteBackward() {
        super.deleteBackward()

        let previousTag = self.tag - 1
        if let previousResponder = self.superview?.viewWithTag(previousTag) {
            previousResponder.becomeFirstResponder()

            if let activeTextField = previousResponder as? UITextField {
                if let isEmpty = activeTextField.text?.isEmpty, !isEmpty {
                    activeTextField.text = String()
                }
            }
        }
    }

}

Variant B (a little bit another behavior):

class EnterConfirmationCodeTextField: UITextField {

    // MARK: Life cycle

    override func awakeFromNib() {
        super.awakeFromNib()

        delegate = self
    }

    // MARK: Methods

    override func deleteBackward() {
        super.deleteBackward()

        let previousTag = self.tag - 1
        if let previousResponder = self.superview?.viewWithTag(previousTag) {
            previousResponder.becomeFirstResponder()
        }
    }

}

Assign EnterConfirmationCodeTextField for each of your textFields and set they appropriate tag value.


You can change the text field like this by using the delegate function of the text field. Initially, you need to set the delegate and the tag of each text field.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if ((textField.text.length >= 1) && (string.length > 0))
    {
        NSInteger nextTag = textField.tag + 1;
        // Try to find next responder
        UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];
        if (! nextResponder)
            nextResponder = [textField.superview viewWithTag:1];

        if (nextResponder)
           // Found next responder, so set it.
           [nextResponder becomeFirstResponder];

        return NO;
    }
    return YES;
}

Swift 2

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    // On inputing value to textfield
    if (textField.text?.characters.count < 1  && string.characters.count > 0){
        let nextTag = textField.tag + 1;

        // get next responder
        var nextResponder = textField.superview?.viewWithTag(nextTag);

        if (nextResponder == nil){
            nextResponder = textField.superview?.viewWithTag(1);
        }
        textField.text = string;
        nextResponder?.becomeFirstResponder();
        return false;
    }
    else if (textField.text?.characters.count >= 1  && string.characters.count == 0){
        // on deleting value from Textfield
        let previousTag = textField.tag - 1;

        // get next responder
        var previousResponder = textField.superview?.viewWithTag(previousTag);

        if (previousResponder == nil){
            previousResponder = textField.superview?.viewWithTag(1);
        }
        textField.text = "";
        previousResponder?.becomeFirstResponder();
        return false;
    }
    return true;
}

Swift 4

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

    if textField.text!.count < 1  && string.count > 0{
        let nextTag = textField.tag + 1

        // get next responder
        var nextResponder = textField.superview?.viewWithTag(nextTag)

        if (nextResponder == nil){

            nextResponder = textField.superview?.viewWithTag(1)
        }
        textField.text = string
        nextResponder?.becomeFirstResponder()
        return false
    }
    else if textField.text!.count >= 1  && string.count == 0{
        // on deleting value from Textfield
        let previousTag = textField.tag - 1

        // get next responder
        var previousResponder = textField.superview?.viewWithTag(previousTag)

        if (previousResponder == nil){
            previousResponder = textField.superview?.viewWithTag(1)
        }
        textField.text = ""
        previousResponder?.becomeFirstResponder()
        return false
    }
    return true

}