Allowing single digit in UITextField in iOS
Solution 1
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
}
Solution 2
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
}
Solution 3
It can be achieve using UITextField delegate & by setting Tag for each Textfield in increasing order (say 1 - 4), below is the delegate handler to solve the issue.
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 deleteing 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;
}
Solution 4
I have taken one Hidden text field & four imageViews for that with two images. One for Blank and other for Bullet same as iOS default.
Also set tags for four imageviews.
On Load set Focus for Pin Code
- (void)startPinCode
{
txtPinCodeLockDigits.text = @"";
for (int i = 1; i <= 4; i++) {
UIImageView *img = (UIImageView *)[self.view viewWithTag:i];
[img setImage:[UIImage imageNamed:@"Img_BG_PinCode.png"]];
}
[txtPinCodeLockDigits becomeFirstResponder];
}
Then change imageview's images as per user input and only allow four characters
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *result = [textField.text stringByReplacingCharactersInRange:range withString:string];
textField.text = result;
for (int i = 1; i <= 4; i++) {
UIImageView *img = (UIImageView *)[self.view viewWithTag:i];
if (i <= [result length])
[img setImage:[UIImage imageNamed:@"Img_BG_PinCode_Filled.png"]];
else
[img setImage:[UIImage imageNamed:@"Img_BG_PinCode.png"]];
}
NSLog(@"Result :: %@", result);
if ([result length] == 4) {
[self performSelector:@selector(keyGenerationForApplication:) withObject:result afterDelay:0.2];
}
return NO;
}
After Four characters call function for generated PIN Code and store it in User Defaults same as iOS default PIN settings
- (void)keyGenerationForApplication:(NSString *)pinCode
{
int appCode = [pinCode intValue];
[DefaultsValues setIntegerValueToUserDefaults:appCode ForKey:PIN_LOCK_PATTERN];
}
Here, you can again call StartPinCode method for re-confirming code.
Hopefully, it'll help you.
Thanks
Solution 5
Modified Anurag Soni's answer in Swift 3.
- It assumes you have outlet collection named
textFields
and the text fields have ordered tags set - It adds case when there's already some digit in text field and when user types something new - the digit is replaced
- Input is restricted to digits only
It prevents from pasting more than one digit
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { // Restrict to only digits let aSet = NSCharacterSet(charactersIn:"0123456789").inverted let compSepByCharInSet = string.components(separatedBy: aSet) let numberFiltered = compSepByCharInSet.joined(separator: "") if string != numberFiltered { return false } // Get the unwrapped text guard let text = textField.text else { return false } if (text.characters.count < 1 && string.characters.count == 1) { // New value to empty text field textField.text = string // Next responder if let someTextField = (textFields.filter { $0.tag == textField.tag + 1 }).first { someTextField.becomeFirstResponder() } else { view.endEditing(true) } return false } else if (text.characters.count >= 1 && string.characters.count == 0){ // On deleting value from Textfield textField.text = "" // Previous responder if let someTextField = (textFields.filter { $0.tag == textField.tag - 1 }).first { someTextField.becomeFirstResponder() } else { view.endEditing(true) } return false } else if string.characters.count == 1 { // There's already some digit in text field // Replace it with new one textField.text = string // Next responder if let someTextField = (textFields.filter { $0.tag == textField.tag + 1 }).first { someTextField.becomeFirstResponder() } else { view.endEditing(true) } } return false }
krish
Updated on June 04, 2022Comments
-
krish almost 2 years
I have a
Verification ViewController
, I get 4 digit verification code by SMS and I need to enter those code to login, I have created theViewController
like thisAs you can see four
UITextField
s, I need to allow only single digit for eachUITextField
,What I tried: I was trying to use
shouldChangeCharactersInRange:method:
, but its not getting called, I don't know what's wrong, I think becauseUITextField
s are inUITableView
so it is not working.