Allowing single digit in UITextField in iOS

前端 未结 13 1276
耶瑟儿~
耶瑟儿~ 2020-12-05 03:55

I have a Verification ViewController, I get 4 digit verification code by SMS and I need to enter those code to login, I have created the ViewController

相关标签:
13条回答
  • 2020-12-05 03:58

    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:

    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.

    0 讨论(0)
  • 2020-12-05 03:59

    It can be achieve using UITextField delegate & by setting Tag for each Textfield in increasing order (say 1 - 4), below is the delegate handler to solve the issue.

    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 deleteing 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;
        }
    
    0 讨论(0)
  • 2020-12-05 03:59

    swift 2.3

          class BankDepositsWithOTPVC: UIViewController {
    
                let limitLength = 1  
    
            override func viewDidLoad() {
                super.viewDidLoad()
            }
    
    
            }
    
            // MARK: Textfield Validator
    
            extension BankDepositsWithOTPVC : UITextFieldDelegate {
    
    
                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
                        let nextResponder = textField.superview?.viewWithTag(nextTag);
    
                        if (nextResponder == nil){
                            textField.resignFirstResponder()
                          //  nextResponder = textField.superview?.viewWithTag(1);
                        }
                        textField.text = string;
                        nextResponder?.becomeFirstResponder();
                        return false;
    
                    }else  if (textField.text?.characters.count >= 1  && string.characters.count > 0){
                                        // maximum 1 digit
    
    textField.text = "";
    
                        let nextTag = textField.tag + 1;
    
                        // get next responder
                        let nextResponder = textField.superview?.viewWithTag(nextTag);
    
                        if (nextResponder == nil){
                            textField.resignFirstResponder()
                            //  nextResponder = textField.superview?.viewWithTag(1);
                        }
                        textField.text = string;
                        nextResponder?.becomeFirstResponder();
                        return false;
                    }
                    else if (textField.text?.characters.count >= 1  && string.characters.count == 0){
                        // on deleteing 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;
    
                    guard let text = textField.text else { return true }
                    let newLength = text.characters.count + string.characters.count - range.length
                    return newLength <= limitLength
    
                }
    
            }
    

    Objective-C

    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
    
        if ((textField.text.length < 1) && (string.length > 0))
        {
    
            NSInteger nextTag = textField.tag + 1;
            UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];
            if (! nextResponder){
                [textField resignFirstResponder];
            }
            textField.text = string;
            if (nextResponder)
                [nextResponder becomeFirstResponder];
    
            return NO;
    
        }else if ((textField.text.length >= 1) && (string.length > 0)){
            //FOR MAXIMUM 1 TEXT
    
            NSInteger nextTag = textField.tag + 1;
            UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];
            if (! nextResponder){
                [textField resignFirstResponder];
            }
            textField.text = string;
            if (nextResponder)
                [nextResponder becomeFirstResponder];
    
            return NO;
        }
        else if ((textField.text.length >= 1) && (string.length == 0)){
            // on deleteing value from Textfield
    
            NSInteger prevTag = textField.tag - 1;
            // Try to find prev responder
            UIResponder* prevResponder = [textField.superview viewWithTag:prevTag];
            if (! prevResponder){
                [textField resignFirstResponder];
            }
            textField.text = string;
            if (prevResponder)
                // Found next responder, so set it.
                [prevResponder becomeFirstResponder];
    
            return NO;
        }
    
          return YES;
    }
    
    0 讨论(0)
  • 2020-12-05 04:00

    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
        }
    
    0 讨论(0)
  • 2020-12-05 04:01

    Swift 4

    when you input a number from the pin code into a text field, you should let a number be shown and then the next text field will become the first responder, so change the first responder after the code was in the text view

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        guard let textField = textField as? PinCodeTextField else { return true }
    
        if string == "" {// when the backward clicked, let it go :)
            return true
        }
    
        // when textfield is not empty, well, next number
        if textField.pinCode.count == textField.maxCount {
            becomeFirstResponder(after: textField)
            return false
        }
    
        if string.count > textField.maxCharacterCount {// the max character count should be 1
            return false
        }
        return true
    }
    // now the text field has been filled with a number
    func textFieldCotentDidChange(_ textField: UITextField) {
        print("didchange")
        guard let textField = textField as? PinCodeTextField else { return }
        if textField.pinCode.count == 0 {
            becomeFirstResponder(before: textField)
        }
    
        // when textfield has been filled, ok! next!
        if textField.pinCode.count == textField.maxCharacterCount {
            becomeFirstResponder(after: textField)
        }
    }
    

    for more details and the simple demo, see this link

    0 讨论(0)
  • 2020-12-05 04:05

    Just use TextFieldDelegate method and check the length of the TextField after every changes

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        let newString = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
        if newString.characters.count == 1
        {
            nextTextField.becomeFirstResponder()
            return true
        }
        else
        {
            return false
        }
    }
    
    0 讨论(0)
提交回复
热议问题