Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift - Automatically jump to next text field when not empty

I am working on a game in which the user has to type out the past tense of a verb. My view contains small textfield boxes that only accept one character. As of now I am trying to automatically jump to the next textfield when the former contains a letter.

I want to keep doing this until all the boxes are filled. The user should also be able to go back one box using the return button on the keyboard.

Below is the code I am currently using, but it is not jumping to the next textfield. What am I doing wrong?

 var game: Game? {
    didSet {

        if var answerContent = game?.answer {

            let views = (0..<answerContent.characters.count).map { _ in UITextField(frame: CGRect(x: 0, y: 0, width: 40, height: 40)) }

            for textField in views {
                textField.backgroundColor = UIColor.white
                textField.textColor = Constants.MAIN_THEME_COLOR
                textField.textAlignment = NSTextAlignment.center
                textField.delegate = self
                textField.returnKeyType = .next
                textField.tag = views.index(of: textField)! + 1
                self.container.addArrangedSubview(textField)

                views.first?.becomeFirstResponder()
            }
        }
    }
}

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    guard let text = textField.text else { return true }
    let textLength = text.characters.count + string.characters.count - range.length

    return textLength <= 1
}

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField {
            print("Test")
            nextField.becomeFirstResponder()
        } else {
            print("Test2")
            textField.resignFirstResponder()
        }

    return false
}

Updated code (24-04-2017) - Returns nil when trying to jump to the next textField

var game: Game? {
    didSet {

if var answerContent = game?.answer {

            let views = (0..<answerContent.characters.count).map { _ in UITextField(frame: CGRect(x: 0, y: 0, width: 40, height: 40)) }

            for textField in views {
                textField.backgroundColor = UIColor.white
                textField.textColor = Constants.MAIN_THEME_COLOR
                textField.textAlignment = NSTextAlignment.center
                textField.delegate = self
                textField.addTarget(self, action: #selector(textChanged), for: .editingChanged)
                textField.tag = views.index(of: textField)! + 1
                self.container.addArrangedSubview(textField)
            }

            views.first?.becomeFirstResponder()
        }
    }
}

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    guard let text = textField.text else { return true }
    let textLength = text.characters.count + string.characters.count - range.length

    return textLength <= 1
}

func textChanged(sender: UITextField) {
    if (sender.text?.characters.count)! > 0 {
        print("Entered")
        let nextField = textField?.superview?.viewWithTag(textField.tag + 1) as UIResponder!

        if (nextField != nil) {
            nextField?.becomeFirstResponder()
        } else {
            print("Error: nil found")
        }
    } else {
        print("Removed")
        textField?.resignFirstResponder()
    }
}

Answer:

var index: NSInteger = 0
for textField in views {
    textField.backgroundColor = UIColor.white
    textField.textColor = Constants.MAIN_THEME_COLOR
    textField.textAlignment = NSTextAlignment.center
    textField.autocapitalizationType = UITextAutocapitalizationType.none
    textField.delegate = self
    textField.addTarget(self, action: #selector(textChanged), for: .editingChanged)
    textField.tag = index
    self.container.addArrangedSubview(textField)

    index+=1
}

func textChanged(sender: UITextField) {
    if (sender.text?.characters.count)! > 0 {
        let nextField = sender.superview?.viewWithTag(sender.tag + 1) as UIResponder!
        nextField?.becomeFirstResponder()
    } else {
        sender.resignFirstResponder()
    }
}
like image 787
Dennis van Mazijk Avatar asked Dec 07 '25 15:12

Dennis van Mazijk


1 Answers

I suggest that you should add a target to the control event .valueChanged:

// for each text field
textField.addTarget(self, action: #selector(textChanged), for: .valueChanged)

Implement textChanged as follows:

func textChanged(sender: UITextField) {
    if sender.text.characters.length > 0 {
        let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField
        nextField?.becomeFistResponder()
    }
}
like image 100
Sweeper Avatar answered Dec 10 '25 22:12

Sweeper



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!