Allowing single digit in UITextField in iOS
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
}
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.
You can change the text field like this by using the delegate function of the text field. Initially, you need to set the delegate and the tag of each text field.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if ((textField.text.length >= 1) && (string.length > 0))
{
NSInteger nextTag = textField.tag + 1;
// Try to find next responder
UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];
if (! nextResponder)
nextResponder = [textField.superview viewWithTag:1];
if (nextResponder)
// Found next responder, so set it.
[nextResponder becomeFirstResponder];
return NO;
}
return YES;
}
Swift 2
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 deleting 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;
}
Swift 4
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField.text!.count < 1 && string.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!.count >= 1 && string.count == 0{
// on deleting 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
}