UITextField:密码实施

时间:2016-04-27 13:41:45

标签: ios objective-c uitextfield uitextfielddelegate

我有一个OTP屏幕,我必须在4个Diff TextFields中输入4位密码的OTP,场景是这样的:

enter image description here

  1. 每个文本字段的最大字符数限制为1,当用户在文本字段中输入字符时,它应移至下一个TextField。
  2. 当用户点击后退空间时,应该返回上一个文本字段以进行更改。
  3. 我已经管理了高达70%的工作,但只有当用户输入所有textField时,后退空间才有效。我正在粘贴我的代码。

    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {
        // This allows numeric text only, but also backspace for deletes
        if (string.length > 0 && ![[NSScanner scannerWithString:string] scanInt:NULL])
            return NO;
    
        NSUInteger oldLength = [textField.text length];
        NSUInteger replacementLength = [string length];
        NSUInteger rangeLength = range.length;
    
        NSUInteger newLength = oldLength - rangeLength + replacementLength;
    
        // This 'tabs' to next field when entering digits
        if (newLength == 1) {
            if (textField == _pin1)
            {
                [self performSelector:@selector(setNextResponder:) withObject:_pin2 afterDelay:0];
            }
            else if (textField ==_pin2)
            {
                [self performSelector:@selector(setNextResponder:) withObject:_pin3 afterDelay:0];
            }
            else if (textField == _pin3)
            {
                [self performSelector:@selector(setNextResponder:) withObject:_pin4 afterDelay:0];
            }
        }
        //this goes to previous field as you backspace through them, so you don't have to tap into them individually
        else if (oldLength > 0 && newLength == 0) {
            if (textField ==_pin4)
            {
                [self performSelector:@selector(setNextResponder:) withObject:_pin3 afterDelay:0];
            }
            else if (textField == _pin3)
            {
                [self performSelector:@selector(setNextResponder:) withObject:_pin2 afterDelay:0];
            }
            else if (textField == _pin2)
            {
                [self performSelector:@selector(setNextResponder:) withObject:_pin1 afterDelay:0];
            }
        }        
        return newLength <= 1;
    }
    
    - (void)setNextResponder:(UITextField *)nextResponder
    {
        [nextResponder becomeFirstResponder];
    }
    

    工作:

    enter image description here

3 个答案:

答案 0 :(得分:7)

需要在UITextView中的StoryBoard中添加标记。

与textField1 = 101一样,textField2 = 102,textField3 = 103,textField4 = 104

enter image description here

将以下代码放入viewcontroller

- (BOOL)keyboardInputShouldDelete:(UITextField *)textField {
    BOOL shouldDelete = YES;

    if ([textField.text length] == 0 && [textField.text isEqualToString:@""]) {
        long tagValue = textField.tag - 1;
        UITextField *txtField = (UITextField*) [self.view viewWithTag:tagValue];

        [txtField becomeFirstResponder];
    }
    return shouldDelete;
}

关注下一个UItextField焦点的代码。

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    // This allows numeric text only, but also backspace for deletes
    if (string.length > 0 && ![[NSScanner scannerWithString:string] scanInt:NULL])
        return NO;

    if ([textField.text length] == 0) {
        [self performSelector:@selector(changeTextFieldFocusToNextTextField:) withObject:textField afterDelay:0.3];
    }

    return YES;
}

-(void)changeTextFieldFocusToNextTextField:(UITextField*)textField{
    long tagValue = textField.tag + 1;
    UITextField *txtField = (UITextField*) [self.view viewWithTag:tagValue];
    [txtField becomeFirstResponder];
}

示例输出

enter image description here

Grab the solution demo project

答案 1 :(得分:2)

原因是当UITextField为empty时,它不会检测到backspace event

因此,要在这种情况下检测退格事件,您必须Subclass UITextField并覆盖deleteBackward方法。

验证以下链接以获取更多详细信息。

Detect backspace in UITextField

编辑:代码已添加。

- 使用以下类对所有4个UITextfield进行子类化。

@protocol MyTextFieldDelegate <NSObject>
@optional
- (void)textFieldDidDelete:(UITextField *)textField;
@end

@interface MyTextField : UITextField<UIKeyInput>

@property (nonatomic, assign) id<MyTextFieldDelegate> myDelegate;
@end

@implementation MyTextField

- (void)deleteBackward {
    [super deleteBackward];

    if ([_myDelegate respondsToSelector:@selector(textFieldDidDelete:)]){
        [_myDelegate textFieldDidDelete:self];
    }
}

@end

- 为所有UITextFields设置委托给自己,并在类中采用MyTextFieldDelegate协议

  _pin1.myDelegate=self;
  _pin2.myDelegate=self;
  _pin3.myDelegate=self;
  _pin4.myDelegate=self;

- 实现textFieldDidDelete方法如下

- (void)textFieldDidDelete:(UITextField *)textField {
    if (textField ==_pin4)
    {
        [self performSelector:@selector(setNextResponder:) withObject:_pin3 afterDelay:0];
    }
    else if (textField == _pin3)
    {
        [self performSelector:@selector(setNextResponder:) withObject:_pin2 afterDelay:0];
    }
    else if (textField == _pin2)
    {
        [self performSelector:@selector(setNextResponder:) withObject:_pin1 afterDelay:0];
    }
}

希望这有帮助。

答案 2 :(得分:0)

对于Swift 3.x

class CodeConfirmController:ViewController,UITextFieldDelegate{

@IBOutlet weak var digitNum1: UITextField!
    @IBOutlet weak var digitNum2: UITextField!
    @IBOutlet weak var digitNum3: UITextField!
    @IBOutlet weak var digitNum4: UITextField!

 override func viewDidLoad() {
        digitNum1.delegate = self
        digitNum2.delegate = self
        digitNum3.delegate = self
        digitNum4.delegate = self
    }

    func keyboardInputShouldDelete(_ textField: UITextField) -> Bool {
        let shouldDelete: Bool = true
        if textField.text?.characters.count == 0 && (textField.text == "") {
            let tagValue: Int = textField.tag - 1
            let txtField: UITextField? = (view.viewWithTag(tagValue) as? UITextField)
            txtField?.becomeFirstResponder()
        }
        return shouldDelete
    }

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        // This allows numeric text only, but also backspace for deletes
        if (string.characters.count ) > 0 && !Scanner(string: string).scanInt32(nil) {
            return false
        }
        if textField.text?.characters.count == 0 {
            perform(#selector(self.changeTextFieldFocus(toNextTextField:)), with: textField, afterDelay: 0.1)
        }
        return true
    }

    func changeTextFieldFocus(toNextTextField textField: UITextField) {
        let tagValue: Int = textField.tag + 1
        let txtField: UITextField? = (view.viewWithTag(tagValue) as? UITextField)
        txtField?.becomeFirstResponder()
    }
}