// // MOInputCodeView.m // MiMoLive // // Created by MiMo on 2025/6/3. // #import "MOInputCodeView.h" @interface MOInputCodeView () @property (nonatomic, strong) UITextField *hiddenField; @property (nonatomic, strong) NSMutableArray *digitLabels; @property (nonatomic, strong) UIView *cursorView; @end @implementation MOInputCodeView - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setupUI]; } return self; } - (void)setupUI { self.digitLabels = [NSMutableArray array]; UIImage *slotBg = [UIImage imageNamed:@"img_login_code_bg"]; CGFloat boxSize = kScaleWidth(64); CGFloat spacing = kScaleWidth(24); NSInteger count = 4; for (int i = 0; i < count; i++) { UIImageView *box = [[UIImageView alloc] initWithImage:slotBg]; box.contentMode = UIViewContentModeScaleToFill; box.userInteractionEnabled = NO; [self addSubview:box]; [box mas_makeConstraints:^(MASConstraintMaker *make) { make.size.mas_equalTo(CGSizeMake(boxSize, boxSize)); make.left.mas_equalTo(i * (boxSize + spacing)); make.top.bottom.equalTo(self); }]; UILabel *label = [[UILabel alloc] init]; label.font = [MOTextTools poppinsMediumFont:32]; label.textAlignment = NSTextAlignmentCenter; label.textColor = kBaseTextColor_1; [box addSubview:label]; [label mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(box); }]; [self.digitLabels addObject:label]; } self.hiddenField = [[UITextField alloc] init]; self.hiddenField.keyboardType = UIKeyboardTypeNumberPad; self.hiddenField.textColor = UIColor.clearColor; self.hiddenField.tintColor = UIColor.clearColor; self.hiddenField.delegate = self; [self.hiddenField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged]; [self addSubview:self.hiddenField]; [self.hiddenField mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self); }]; self.cursorView = [[UIView alloc] init]; self.cursorView.backgroundColor = [MOTools colorWithHexString:@"#4363FF"]; self.cursorView.hidden = YES; self.cursorView.layer.cornerRadius = 1; self.cursorView.layer.masksToBounds = YES; [self addSubview:self.cursorView]; [self.cursorView mas_makeConstraints:^(MASConstraintMaker *make) { make.width.mas_equalTo(2); make.height.mas_equalTo(24); make.center.equalTo(self); // 初始占位,稍后更新位置 }]; // 添加光标闪烁动画 CABasicAnimation *blink = [CABasicAnimation animationWithKeyPath:@"opacity"]; blink.fromValue = @1.0; blink.toValue = @0.0; blink.duration = 0.8; blink.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; blink.autoreverses = YES; blink.repeatCount = HUGE_VALF; [self.cursorView.layer addAnimation:blink forKey:@"blink"]; } - (void)showKeyboard { [self.hiddenField becomeFirstResponder]; [self moveCursorToIndex:0]; } - (void)textFieldDidChange:(UITextField *)textField { NSString *text = textField.text; if (text.length > 4) { text = [text substringToIndex:4]; textField.text = text; } for (int i = 0; i < 4; i++) { UILabel *label = self.digitLabels[i]; if (i < text.length) { label.text = [text substringWithRange:NSMakeRange(i, 1)]; } else { label.text = @""; } } if (text.length == 4 && self.inputCompleted) { self.inputCompleted(text); } NSInteger index = text.length; // 下一个待输入框索引 if (index >= 0 && index < self.digitLabels.count) { UILabel *targetLabel = self.digitLabels[index]; [self.cursorView mas_remakeConstraints:^(MASConstraintMaker *make) { make.width.mas_equalTo(2); make.height.mas_equalTo(24); make.center.equalTo(targetLabel); }]; self.cursorView.hidden = NO; } else { self.cursorView.hidden = YES; } } - (void)clear { self.hiddenField.text = @""; for (UILabel *label in self.digitLabels) { label.text = @""; } self.cursorView.hidden = NO; [self moveCursorToIndex:0]; } - (void)moveCursorToIndex:(NSInteger)index { if (index >= 0 && index < self.digitLabels.count) { UILabel *targetLabel = self.digitLabels[index]; [self.cursorView mas_remakeConstraints:^(MASConstraintMaker *make) { make.width.mas_equalTo(2); make.height.mas_equalTo(24); make.center.equalTo(targetLabel); }]; self.cursorView.hidden = NO; } else { self.cursorView.hidden = YES; } } @end