skip to Main Content

I am working on Swift application, In that I have OTP verification screen.
So, User can enters 6 digits otp in 6 textfields.
I have created collection view and in that cell I have added dynamically 6 cells.
I am able to entering text and validating.

But, My requirement is once first digit fills, automatically cursor should move to next one.

My code is below

    var insertedValues = [String]()
    private var arrayOfCells: [OtpCollectionViewCell] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        let cellSize = CGSize(width:50 , height:50)
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .vertical //.horizontal
        layout.itemSize = cellSize
        layout.sectionInset = UIEdgeInsets(top: 1, left: 1, bottom: 1, right: 1)
        layout.minimumLineSpacing = 1.0
        layout.minimumInteritemSpacing = 1.0
        collectionView.setCollectionViewLayout(layout, animated: true)

     }

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        
        return 6 // this may be dynamic count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "OtpCollectionViewCell", for: indexPath) as! OtpCollectionViewCell
        cell.otpTextField.tag = indexPath.row
        cell.otpTextField.delegate = self
        arrayOfCells += [cell]
        return cell
    }

    func textFieldDidEndEditing(_ textField: UITextField) {
        
        if insertedValues.count > 0 {
            insertedValues.removeAll()
        }
        
        for i in 0..<arrayOfCells.count {
            if let textfieldText = arrayOfCells[i].otpTextField.text, textfieldText != "" {
                insertedValues.append(textfieldText)
                if insertedValues.count == 6 {
                    textField.resignFirstResponder()
                    self.performAPICall()
                }
            }
        }
    }
    
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        
        if range.location == 0 && string == " " { //restrict single and double space tap
            return false
        }
        let currentCharacterCount = textField.text?.count ?? 0
        if range.length + range.location > currentCharacterCount {
            return false
        }
        let newLength = currentCharacterCount + string.count - range.length
        return newLength <= 1
    }

Here is my screen looks like.

enter image description here
Any Suggestions?

2

Answers


  1. Chosen as BEST ANSWER

    I have followed above solution, But, there is much code if there are more otp textfields. So, I have optimised solution.

    Because in future, We may increase OTP textfields count like 10, 12. So, that is the purpose, I followed dynamic cells(Textfields) using collection view.

    Here is my code

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            
            if (textField.text?.count)! < 1 && string.count > 0 { // for moving cursor to next field
                
                for i in 0..<arrayOfCells.count - 1 {
                    if textField == arrayOfCells[i].otpTextField {
                        arrayOfCells[i+1].otpTextField.becomeFirstResponder()
                    }
                }
                textField.text = string
                return false
                
            }
            else if (textField.text?.count)! >= 1 && string.count == 0 {
                
                for i in 0..<arrayOfCells.count - 1 {
                     
                    if textField == arrayOfCells[i+1].otpTextField {
                        arrayOfCells[i].otpTextField.becomeFirstResponder()
                    }
                }
                
                textField.text = string
                return false
            }
            
            else if (textField.text?.count)! >= 1 {
                textField.text = string
                return false
            }
    }
    

    This code is working as I expected!


  2. This is the logic of moving cursor b/w textfields of OTP just map to your collectionview otp cells

         func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    
        if (textField.text?.count)! < 1 && string.count > 0 {
            
            if textField == textOne {
                textTwo.becomeFirstResponder()
            }
            
            if textField == textTwo {
                textThree.becomeFirstResponder()
            }
            
            if textField == textThree {
                textFour.becomeFirstResponder()
            }
            
            if textField == textFour {
                textFive.becomeFirstResponder()
            }
            
            if textField == textFive {
                textSix.becomeFirstResponder()
            }
            
            if textField == textSix {
                textSix.resignFirstResponder()
            }
            
            textField.text = string
            return false
            
        }
        
        else if (textField.text?.count)! >= 1 && string.count == 0 {
            
            if textField == textTwo {
                textOne.becomeFirstResponder()
            }
            
            if (textField == textThree) {
                textTwo.becomeFirstResponder()
            }
            
            if (textField == textFour) {
                textThree.becomeFirstResponder()
            }
            
            if (textField == textFive) {
                textFour.becomeFirstResponder()
            }
            
            if (textField == textSix) {
                textFive.becomeFirstResponder()
            }
            
            if (textField == textOne) {
                textOne.resignFirstResponder()
            }
            
            textField.text = string
            return false
            
        }
        
        else if (textField.text?.count)! >= 1 {
            textField.text = string
            return false
        }
        
        return true
        
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search