Home > front end >  How to move cursor to next textfield automatically after fill previous textfield in Swift Collection
How to move cursor to next textfield automatically after fill previous textfield in Swift Collection

Time:07-01

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?

CodePudding user response:

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
    
}

CodePudding user response:

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!

  • Related