头文件:
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface YXInputCodeView : UIView
@property (nonatomic, strong) UIFont *codeFont;
@property (nonatomic, strong) UIColor *codeColor;
/// 每个code的size
@property (nonatomic, assign) CGSize itemSize;
@property (nonatomic, strong) UIColor *itemBorderColor;
@property (nonatomic, assign) CGFloat itemBorderWidth;
@property (nonatomic, assign) CGFloat itemPadding;
/// 光标size
@property (nonatomic, assign) CGSize cursorSize;
/// 光标颜色
@property (nonatomic, strong) UIColor *cursorColor;
@property (nonatomic, copy) void (^didChangeBlock)(NSString *);
+ (instancetype)inputCodeViewWith:(NSInteger)count;
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END
实现:
#import "YXInputCodeView.h"
#define kOpacityAnimation @"kOpacityAnimation"
@interface YXInputCodeItem: UIView
@property (nonatomic, strong) CAShapeLayer *cursorLayer;
@property (nonatomic, strong) UILabel *textLabel;
@property (nonatomic, assign) CGSize cursorSize;
- (void)hideCursor;
- (void)showCursorWithAnima:(CABasicAnimation *)anima;
@end
@interface YXInputCodeView()
@property (nonatomic, strong) NSMutableArray *itemArr;
@property (nonatomic, strong) UITextField *mTextField;
@property (nonatomic, strong) CABasicAnimation *opacityAnimation;
@property (nonatomic, copy) NSString *codeStr;
@end
@implementation YXInputCodeView
+ (instancetype)inputCodeViewWith:(NSInteger)count {
if (count<=0) {
count = 4;
}
YXInputCodeView *input = [[self alloc] init];
input.itemArr = [NSMutableArray arrayWithCapacity:count];
CGSize size = input.itemSize;
for (int i = 0; i<count; i++) {
YXInputCodeItem *itemView = [[YXInputCodeItem alloc] init];
itemView.textLabel.textColor = input.codeColor;
itemView.textLabel.font = input.codeFont;
itemView.cursorLayer.fillColor = input.cursorColor.CGColor;
itemView.cursorSize = input.cursorSize;
if (i == 0) {
[itemView showCursorWithAnima:input.opacityAnimation];
}else {
[itemView hideCursor];
}
itemView.layer.borderColor = input.itemBorderColor.CGColor;
itemView.layer.borderWidth = input.itemBorderWidth;
itemView.frame = CGRectMake(i*(size.width+input.itemPadding), 0, size.width, size.height);
[input.itemArr addObject:itemView];
[input addSubview:itemView];
}
input.frame = CGRectMake(0, 0, size.width*count, size.height);
[input.mTextField becomeFirstResponder];
return input;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self.mTextField becomeFirstResponder];
}
- (instancetype)init {
self = [super init];
if (self) {
self.codeColor = [UIColor blackColor];
self.itemBorderColor = [UIColor purpleColor];
self.codeFont = [UIFont boldSystemFontOfSize:20];
self.itemSize = CGSizeMake(44, 44);
self.cursorColor = [UIColor purpleColor];
self.cursorSize = CGSizeMake(2, 30);
self.itemPadding = 10;
self.itemBorderWidth = 2;
[self addSubview:self.mTextField];
}
return self;
}
- (void)textFieldDidChange:(UITextField *)textField {
NSInteger codeCount = _itemArr.count;
if (textField.text.length >= codeCount) {
[self endInput];
}
_codeStr = textField.text;
if (self.didChangeBlock) {
self.didChangeBlock(_codeStr);
}
[self updateItem];
}
- (void)updateItem {
NSInteger count = _itemArr.count;
for (int i = 0; i < count; i++) {
YXInputCodeItem *codeItem = _itemArr[i];
if (i < _codeStr.length) {
[codeItem hideCursor];
codeItem.textLabel.text = [_codeStr substringWithRange:NSMakeRange(i, 1)];
}else {
if (i==_codeStr.length) {
[codeItem showCursorWithAnima:self.opacityAnimation];
}else {
[codeItem hideCursor];
}
codeItem.textLabel.text = @"";
}
}
}
- (void)endInput {
[_mTextField resignFirstResponder];
}
- (UITextField *)mTextField {
if (!_mTextField) {
_mTextField = [[UITextField alloc] init];
_mTextField.keyboardType = UIKeyboardTypeNumberPad;
_mTextField.tintColor = [UIColor clearColor];
_mTextField.backgroundColor = [UIColor clearColor];
_mTextField.textColor = [UIColor clearColor];
[_mTextField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
}
return _mTextField;
}
- (CABasicAnimation *)opacityAnimation {
if (!_opacityAnimation) {
_opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
_opacityAnimation.fromValue = @(1.0);
_opacityAnimation.toValue = @(0);
_opacityAnimation.duration = 1.0;
_opacityAnimation.repeatCount = MAXFLOAT;
_opacityAnimation.removedOnCompletion = YES;
_opacityAnimation.fillMode = kCAFillModeForwards;
_opacityAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
}
return _opacityAnimation;
}
@end
@implementation YXInputCodeItem
- (void)hideCursor {
_cursorLayer.hidden = YES;
[_cursorLayer removeAllAnimations];
}
- (void)showCursorWithAnima:(CABasicAnimation *)anima {
_cursorLayer.hidden = NO;
[_cursorLayer addAnimation:anima forKey:kOpacityAnimation];
}
- (instancetype)init {
self = [super init];
if (self) {
[self addSubview:self.textLabel];
[self.layer addSublayer:self.cursorLayer];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
self.textLabel.frame = self.bounds;
CGFloat pathX = (self.bounds.size.width-self.cursorSize.width)/2.0;
CGFloat pathY = (self.bounds.size.height-self.cursorSize.height)/2.0;
CGRect pathRect = CGRectMake(pathX, pathY, self.cursorSize.width, self.cursorSize.height);
UIBezierPath *path = [UIBezierPath bezierPathWithRect:pathRect];
_cursorLayer.path = path.CGPath;
}
- (CAShapeLayer *)cursorLayer {
if (!_cursorLayer) {
_cursorLayer = [[CAShapeLayer alloc] init];
_cursorLayer.hidden = YES;
}
return _cursorLayer;
}
- (UILabel *)textLabel {
if (!_textLabel) {
_textLabel = [[UILabel alloc] init];
_textLabel.textAlignment = NSTextAlignmentCenter;
}
return _textLabel;
}
@end