当前我们很多 app 都有六位密码输入的界面,如常见的 支付宝 微信 以及 各家银行类 app 等等。

这次公司项目也有一个类似的界面,是输入验证码,而且输入框的 layer 还会根据是否输入的状态来改变。

我打算直接用 TextField 来写一个,由于是第一次写所以判断的逻辑和代码比较复杂,后续有机会会有优化。

思路及部分代码展示

自定义 TextField.h:

@class CertificatePasswordTextField;

@protocol CPTextFieldDelegate <NSObject>

- (void)cpTextFieldDeleteBackward:(CertificatePasswordTextField *)textField;

@end

@interface CertificatePasswordTextField : UITextField

@property (nonatomic, assign) id <CPTextFieldDelegate> cp_delegate;

@end

自定义 TextField.m:

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        self.textAlignment = NSTextAlignmentCenter;
        self.keyboardType = UIKeyboardTypeNumberPad;
        [self setTintColor:[UIColor clearColor]]; // 光标隐藏,可根据需要设置
        self.alpha = 0.3;
        self.layer.cornerRadius = 5;
        self.layer.borderWidth = 1;
        self.layer.borderColor = [UIColor blueColor].CGColor;
    }
    return self;
}

- (void)deleteBackward {
    [super deleteBackward];
    if ([self.cp_delegate respondsToSelector:@selector(cpTextFieldDeleteBackward:)]) {
        [self.cp_delegate cpTextFieldDeleteBackward:self];
    }
}

controller中代码 (部分)

@interface ViewController ()<UITextFieldDelegate, CPTextFieldDelegate>

@property (nonatomic, strong) CertificatePasswordTextField *oneText;
@property (nonatomic, strong) CertificatePasswordTextField *twoText;
@property (nonatomic, strong) CertificatePasswordTextField *threeText;
@property (nonatomic, strong) CertificatePasswordTextField *fourText;
@property (nonatomic, strong) CertificatePasswordTextField *fiveText;
@property (nonatomic, strong) CertificatePasswordTextField *sixText;

@property (nonatomic, strong) NSMutableArray *passwordArray;

@end

#pragma mark - CP Text Field Delegate

- (void)cpTextFieldDeleteBackward:(CertificatePasswordTextField *)textField {
    // 若输入中断再次输入时可以立即定位并唤起正确第一响应者
    if ([textField.text isEqualToString:@""]) {
        textField.text = @"";
        if ([textField isEqual:self.sixText]) {
            [self.fiveText becomeFirstResponder];
        } else if ([textField isEqual:self.fiveText]) {
            [self.fourText becomeFirstResponder];
        } else if ([textField isEqual:self.fourText]) {
            [self.threeText becomeFirstResponder];
        } else if ([textField isEqual:self.threeText]) {
            [self.twoText becomeFirstResponder];
        } else if ([textField isEqual:self.twoText]) {
            [self.oneText becomeFirstResponder];
        }
    }
}

#pragma mark - Text Field Delegate

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
    // 若当前 textfield 有输入内容则变色
    if ([textField isEqual:self.oneText] && self.twoText.text.length < 1) {
        textField.alpha = 1;
           return YES;
    } else if ([textField isEqual:self.twoText] && self.threeText.text.length < 1) {
        if (self.oneText.text.length > 0) {
            textField.alpha = 1;
            return YES;
        }
    } else if ([textField isEqual:self.threeText] && self.fourText.text.length < 1) {
        if (self.twoText.text.length > 0) {
            textField.alpha = 1;
            return YES;
        }
    } else if ([textField isEqual:self.fourText] && self.fiveText.text.length < 1) {
        if (self.threeText.text.length > 0) {
            textField.alpha = 1;
            return YES;
        }
    } else if ([textField isEqual:self.fiveText] && self.sixText.text.length < 1) {
        if (self.fourText.text.length > 0) {
            textField.alpha = 1;
            return YES;
        }
    } else if ([textField isEqual:self.sixText]) {
        if (self.fiveText.text.length > 0) {
            textField.alpha = 1;
            return YES;
        }
    }
    return NO;
}

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    // 根据输入判断是否改变 layer 颜色
    if (textField.text.length > 0) {
        textField.alpha = 1;
    } else {
        textField.alpha = 0.3;
    }
    if (textField.text.length > 1) {
        // 经测试 iOS13 以上在通过键盘一次性多位输入会出现第一个 TexitField 多位输入
        textField.text = [textField.text substringWithRange:NSMakeRange(0, 1)];
    }
    return YES;
}

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    if (textField.text.length < 1 || [string isEqualToString:@""]) {
        // 对 textfield 应位 array 输入记录
        if ([textField isEqual:self.oneText]) {
            [self.passwordArray replaceObjectAtIndex:0 withObject:string];
        } else if ([textField isEqual:self.twoText]) {
            [self.passwordArray replaceObjectAtIndex:1 withObject:string];
        } else if ([textField isEqual:self.threeText]) {
            [self.passwordArray replaceObjectAtIndex:2 withObject:string];
        } else if ([textField isEqual:self.fourText]) {
            [self.passwordArray replaceObjectAtIndex:3 withObject:string];
        } else if ([textField isEqual:self.fiveText]) {
            [self.passwordArray replaceObjectAtIndex:4 withObject:string];
        } else if ([textField isEqual:self.sixText]) {
            [self.passwordArray replaceObjectAtIndex:5 withObject:string];
        }
        return YES;
    }
    // 若输入中断再次输入时可以立即定位并唤起正确第一响应者
    if ([textField isEqual:self.oneText]) {
        self.twoText.text = string;
        [self.twoText becomeFirstResponder];
    } else if ([textField isEqual:self.twoText]) {
        self.threeText.text = string;
        [self.threeText becomeFirstResponder];
    } else if ([textField isEqual:self.threeText]) {
        self.fourText.text = string;
        [self.fourText becomeFirstResponder];
    } else if ([textField isEqual:self.fourText]) {
        self.fiveText.text = string;
        [self.fiveText becomeFirstResponder];
    } else if ([textField isEqual:self.fiveText]) {
        self.sixText.text = string;
        [self.sixText becomeFirstResponder];
    }
    return NO;
}

至此,主要的核心代码及实录已经展示完毕,下面来看一下最终效果图:

不看代码的话效果非常不错!

本文源码:CurrentDateChooseDatePicker

欢迎大家提问指教!