iosswifttextfielduitextfielddelegate

How to detect otp type empty textfield swift ios


I'v ten textfields like otp for mobile number.I've handled all cases except like if user write digit in first textfield and focus goes to second textfield.Second textfield is empty and when i press the delete button focus not goes to pervious field.So, how i can handle empty textfield case when textfield is empty and user press the delete button.

 @IBOutlet weak var textFieldNumber1: UITextField!
    @IBOutlet weak var textFieldNumber2: UITextField!
    @IBOutlet weak var textFieldNumber3: UITextField!
    @IBOutlet weak var textFieldNumber4: UITextField!
    @IBOutlet weak var textFieldNumber5: UITextField!
    @IBOutlet weak var textFieldNumber6: UITextField!
    @IBOutlet weak var textFieldNumber7: UITextField!
    @IBOutlet weak var textFieldNumber8: UITextField!
    @IBOutlet weak var textFieldNumber9: UITextField!
    @IBOutlet weak var textFieldNumber10: UITextField!
    @IBOutlet weak var textFieldPassword: UITextField!
  func setupTextFields() {
        [textFieldNumber1,textFieldNumber2,textFieldNumber3,textFieldNumber4,textFieldNumber5,textFieldNumber6,textFieldNumber7,textFieldNumber8,textFieldNumber9,textFieldNumber10].forEach {
            $0?.keyboardType = .numberPad
            $0?.delegate = self
            $0?.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
        }
    }

   @objc func textFieldDidChange(_ textField: UITextField) {
        guard let text = textField.text else {return}
        let char =  text.cString(using: String.Encoding.utf8)
        let isBackSpace = strcmp(char, "\\b")
        if isBackSpace == -92 {
            switch textField.tag {
            case 1:
                counterTextFieldPhoneNumber -= 1
            case 2:
                textFieldNumber1.becomeFirstResponder()
                counterTextFieldPhoneNumber -= 1
            case 3:
                textFieldNumber2.becomeFirstResponder()
                counterTextFieldPhoneNumber -= 1
            case 4:
                textFieldNumber3.becomeFirstResponder()
                counterTextFieldPhoneNumber -= 1
            case 5:
                textFieldNumber4.becomeFirstResponder()
                counterTextFieldPhoneNumber -= 1
            case 6:
                textFieldNumber5.becomeFirstResponder()
                counterTextFieldPhoneNumber -= 1
            case 7:
                textFieldNumber6.becomeFirstResponder()
                counterTextFieldPhoneNumber -= 1
            case 8:
                textFieldNumber7.becomeFirstResponder()
                counterTextFieldPhoneNumber -= 1
            case 9:
                textFieldNumber8.becomeFirstResponder()
                counterTextFieldPhoneNumber -= 1
            case 10:
                textFieldNumber9.becomeFirstResponder()
                counterTextFieldPhoneNumber -= 1
            default:
                break
            }
        }  
    }

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let char = string.cString(using: String.Encoding.utf8)
        let isBackSpace = strcmp(char, "\\b")
        if !(isBackSpace == -92) {
            if (counterTextFieldPhoneNumber >= 0 || counterTextFieldPhoneNumber <= 10) {
                switch textField.tag {
                case 1:
                    textFieldNumber1.text = string
                    textFieldNumber2.becomeFirstResponder()
                    textFieldNumber2.text = ""
                    counterTextFieldPhoneNumber += 1
                case 2:
                    textFieldNumber2.text = string
                    textFieldNumber3.becomeFirstResponder()
                    textFieldNumber3.text = ""
                    counterTextFieldPhoneNumber += 1
                case 3:
                    textFieldNumber3.text = string
                    textFieldNumber4.becomeFirstResponder()
                    textFieldNumber4.text = ""
                    counterTextFieldPhoneNumber += 1
                case 4:
                    textFieldNumber4.text = string
                    textFieldNumber5.becomeFirstResponder()
                    textFieldNumber5.text = ""
                    counterTextFieldPhoneNumber += 1
                case 5:
                    textFieldNumber5.text = string
                    textFieldNumber6.becomeFirstResponder()
                    textFieldNumber6.text = ""
                    counterTextFieldPhoneNumber += 1
                case 6:
                    textFieldNumber6.text = string
                    textFieldNumber7.becomeFirstResponder()
                    textFieldNumber7.text = ""
                    counterTextFieldPhoneNumber += 1
                case 7:
                    textFieldNumber7.text = string
                    textFieldNumber8.becomeFirstResponder()
                    textFieldNumber8.text = ""
                    counterTextFieldPhoneNumber += 1
                case 8:
                    textFieldNumber8.text = string
                    textFieldNumber9.becomeFirstResponder()
                    textFieldNumber9.text = ""
                    counterTextFieldPhoneNumber += 1
                case 9:
                    textFieldNumber9.text = string
                    textFieldNumber10.becomeFirstResponder()
                    textFieldNumber10.text = ""
                    counterTextFieldPhoneNumber += 1
                case 10:
                    textFieldNumber10.text = string
                    textFieldNumber10.resignFirstResponder()
                    counterTextFieldPhoneNumber += 1
                    
                    guard let tf1 = textFieldNumber1.text,
                          let tf2 = textFieldNumber2.text,
                          let tf3 = textFieldNumber3.text,
                          let tf4 = textFieldNumber4.text,
                          let tf5 = textFieldNumber5.text,
                          let tf6 = textFieldNumber6.text,
                          let tf7 = textFieldNumber7.text,
                          let tf8 = textFieldNumber8.text,
                          let tf9 = textFieldNumber9.text,
                          let tf10 = textFieldNumber10.text
                    else {return false}
                    if tf1.isEmpty || tf2.isEmpty || tf3.isEmpty || tf4.isEmpty || tf5.isEmpty || tf6.isEmpty || tf7.isEmpty || tf8.isEmpty || tf9.isEmpty || tf10.isEmpty {return false}
                    viewModel.phoneNumber = "\(tf1)\(tf2)\(tf3)\(tf4)\(tf5)\(tf6)\(tf7)\(tf8)\(tf9)\(tf10)"

                default:
                    break
                }
            }
        }
        return true
    }

Solution

  • You can call this function 'deleteBackward' for every UITextField

    public override func deleteBackward() {
        super.deleteBackward()
        // Logic for cursor move one field to another
    }
    

    Example: https://github.com/amitcse6/ASOtpTextField

    CustomTextField:

    public override func deleteBackward() {
        super.deleteBackward()
        customDelegate?.textFieldDidDelete(self)
    }
        
    

    ViewController:

    extension ASOtpTextFieldView: ASOtpTextFieldDelegate {
        public func textFieldDidDelete(_ textField: ASOtpField) {
            let updatedText = textField.text ?? ""
            if updatedText.count == 0 {
                goPreviousField(selectedTextField: textField)
            }
        }
    }
    
    func goPreviousField(selectedTextField: ASOtpField) {
        if let textFields = textFields {
            textFields.forEach({ (textField) in
                if selectedTextField.index == textField.index, selectedTextField.index > 0 {
                    DispatchQueue.main.async {
                        selectedTextField.resignFirstResponder()
                        textFields[selectedTextField.index-1].textField?.becomeFirstResponder()
                    }
                    return
                }
            })
        }
    }