Compare commits
10 Commits
7a7938e1b4
...
f00a31ecf3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f00a31ecf3 | ||
|
|
7bff9289f6 | ||
|
|
8c76b2651f | ||
|
|
295eec3f77 | ||
|
|
0b89268d9f | ||
|
|
b9d1b3a12f | ||
|
|
354ec92a31 | ||
|
|
1ab7348e27 | ||
|
|
e45fb8260e | ||
|
|
a7290c68ab |
@@ -16,6 +16,7 @@
|
||||
87BA7284215B3E3B00A6911D /* HWTFCodeBView.m in Sources */ = {isa = PBXBuildFile; fileRef = 87BA727E215B3E3B00A6911D /* HWTFCodeBView.m */; };
|
||||
87BA7285215B3E3B00A6911D /* HWTFCodeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 87BA727F215B3E3B00A6911D /* HWTFCodeView.m */; };
|
||||
87BA7286215B3E3B00A6911D /* HWTextCodeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 87BA7280215B3E3B00A6911D /* HWTextCodeView.m */; };
|
||||
87DCFBBE21C26B2100D4C08D /* HWTFCursorView.m in Sources */ = {isa = PBXBuildFile; fileRef = 87DCFBBD21C26B2100D4C08D /* HWTFCursorView.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
@@ -35,6 +36,8 @@
|
||||
87BA7281215B3E3B00A6911D /* HWTFCodeBView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HWTFCodeBView.h; sourceTree = "<group>"; };
|
||||
87BA7282215B3E3B00A6911D /* HWTextCodeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HWTextCodeView.h; sourceTree = "<group>"; };
|
||||
87BA7283215B3E3B00A6911D /* HWTFCodeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HWTFCodeView.h; sourceTree = "<group>"; };
|
||||
87DCFBBC21C26B2100D4C08D /* HWTFCursorView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HWTFCursorView.h; sourceTree = "<group>"; };
|
||||
87DCFBBD21C26B2100D4C08D /* HWTFCursorView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HWTFCursorView.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -90,6 +93,8 @@
|
||||
87BA727E215B3E3B00A6911D /* HWTFCodeBView.m */,
|
||||
87BA7283215B3E3B00A6911D /* HWTFCodeView.h */,
|
||||
87BA727F215B3E3B00A6911D /* HWTFCodeView.m */,
|
||||
87DCFBBC21C26B2100D4C08D /* HWTFCursorView.h */,
|
||||
87DCFBBD21C26B2100D4C08D /* HWTFCursorView.m */,
|
||||
);
|
||||
path = CodeTextView;
|
||||
sourceTree = "<group>";
|
||||
@@ -168,6 +173,7 @@
|
||||
87BA726C215B3DC200A6911D /* ViewController.m in Sources */,
|
||||
87BA7277215B3DC300A6911D /* main.m in Sources */,
|
||||
87BA7269215B3DC200A6911D /* AppDelegate.m in Sources */,
|
||||
87DCFBBE21C26B2100D4C08D /* HWTFCursorView.m in Sources */,
|
||||
87BA7284215B3E3B00A6911D /* HWTFCodeBView.m in Sources */,
|
||||
87BA7286215B3E3B00A6911D /* HWTextCodeView.m in Sources */,
|
||||
);
|
||||
|
||||
51
CodeTextDemo/CodeTextView/HWTFCursorView.h
Normal file
51
CodeTextDemo/CodeTextView/HWTFCursorView.h
Normal file
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// HWTFCursorView.h
|
||||
// CodeTextDemo
|
||||
//
|
||||
// Created by 侯万 on 2018/12/13.
|
||||
// Copyright © 2018 小侯爷. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
||||
/**
|
||||
基础版 - 下划线 - 有光标
|
||||
*/
|
||||
@interface HWTFCursorView : UIView
|
||||
|
||||
|
||||
// ----------------------------Data----------------------------
|
||||
/// 当前输入的内容
|
||||
@property (nonatomic, copy, readonly) NSString *code;
|
||||
|
||||
|
||||
// ----------------------------Method----------------------------
|
||||
|
||||
- (instancetype)initWithCount:(NSInteger)count margin:(CGFloat)margin;
|
||||
|
||||
- (instancetype)init UNAVAILABLE_ATTRIBUTE;
|
||||
+ (instancetype)new UNAVAILABLE_ATTRIBUTE;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// -----------------------------HWCursorLabel------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
|
||||
@interface HWCursorLabel : UILabel
|
||||
|
||||
@property (nonatomic, weak, readonly) UIView *cursorView;
|
||||
|
||||
- (void)startAnimating;
|
||||
- (void)stopAnimating;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
248
CodeTextDemo/CodeTextView/HWTFCursorView.m
Normal file
248
CodeTextDemo/CodeTextView/HWTFCursorView.m
Normal file
@@ -0,0 +1,248 @@
|
||||
//
|
||||
// HWTFCursorView.m
|
||||
// CodeTextDemo
|
||||
//
|
||||
// Created by 侯万 on 2018/12/13.
|
||||
// Copyright © 2018 小侯爷. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HWTFCursorView.h"
|
||||
|
||||
@interface HWTFCursorView ()
|
||||
|
||||
@property (nonatomic, assign) NSInteger itemCount;
|
||||
|
||||
@property (nonatomic, assign) CGFloat itemMargin;
|
||||
|
||||
@property (nonatomic, weak) UITextField *textField;
|
||||
|
||||
@property (nonatomic, weak) UIControl *maskView;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray<HWCursorLabel *> *labels;
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray<UIView *> *lines;
|
||||
|
||||
@property (nonatomic, weak) HWCursorLabel *currentLabel;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@implementation HWTFCursorView
|
||||
|
||||
#pragma mark - 初始化
|
||||
- (instancetype)initWithCount:(NSInteger)count margin:(CGFloat)margin
|
||||
{
|
||||
if (self = [super init]) {
|
||||
|
||||
self.itemCount = count;
|
||||
self.itemMargin = margin;
|
||||
|
||||
[self configTextField];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)configTextField
|
||||
{
|
||||
self.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
self.labels = @[].mutableCopy;
|
||||
self.lines = @[].mutableCopy;
|
||||
|
||||
UITextField *textField = [[UITextField alloc] init];
|
||||
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
||||
textField.keyboardType = UIKeyboardTypeNumberPad;
|
||||
[textField addTarget:self action:@selector(tfEditingChanged:) forControlEvents:(UIControlEventEditingChanged)];
|
||||
|
||||
// 小技巧:这个属性为YES,可以强制使用系统的数字键盘,缺点是重新输入时,会清空之前的内容
|
||||
// clearsOnBeginEditing 属性并不适用于 secureTextEntry = YES 时
|
||||
// textField.secureTextEntry = YES;
|
||||
|
||||
[self addSubview:textField];
|
||||
self.textField = textField;
|
||||
|
||||
// 小技巧:通过textField上层覆盖一个maskView,可以去掉textField的长按事件
|
||||
UIButton *maskView = [UIButton new];
|
||||
maskView.backgroundColor = [UIColor whiteColor];
|
||||
[maskView addTarget:self action:@selector(clickMaskView) forControlEvents:(UIControlEventTouchUpInside)];
|
||||
[self addSubview:maskView];
|
||||
self.maskView = maskView;
|
||||
|
||||
for (NSInteger i = 0; i < self.itemCount; i++)
|
||||
{
|
||||
HWCursorLabel *label = [HWCursorLabel new];
|
||||
label.textAlignment = NSTextAlignmentCenter;
|
||||
label.textColor = [UIColor darkTextColor];
|
||||
label.font = [UIFont fontWithName:@"PingFangSC-Regular" size:41.5];
|
||||
[self addSubview:label];
|
||||
[self.labels addObject:label];
|
||||
}
|
||||
|
||||
for (NSInteger i = 0; i < self.itemCount; i++)
|
||||
{
|
||||
UIView *line = [UIView new];
|
||||
line.backgroundColor = [UIColor purpleColor];
|
||||
[self addSubview:line];
|
||||
[self.lines addObject:line];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
|
||||
if (self.labels.count != self.itemCount) return;
|
||||
|
||||
CGFloat temp = self.bounds.size.width - (self.itemMargin * (self.itemCount - 1));
|
||||
CGFloat w = temp / self.itemCount;
|
||||
CGFloat x = 0;
|
||||
|
||||
for (NSInteger i = 0; i < self.labels.count; i++)
|
||||
{
|
||||
x = i * (w + self.itemMargin);
|
||||
|
||||
UILabel *label = self.labels[i];
|
||||
label.frame = CGRectMake(x, 0, w, self.bounds.size.height);
|
||||
|
||||
UIView *line = self.lines[i];
|
||||
line.frame = CGRectMake(x, self.bounds.size.height - 1, w, 1);
|
||||
}
|
||||
|
||||
self.textField.frame = self.bounds;
|
||||
self.maskView.frame = self.bounds;
|
||||
}
|
||||
|
||||
#pragma mark - 编辑改变
|
||||
- (void)tfEditingChanged:(UITextField *)textField
|
||||
{
|
||||
if (textField.text.length > self.itemCount) {
|
||||
textField.text = [textField.text substringWithRange:NSMakeRange(0, self.itemCount)];
|
||||
}
|
||||
|
||||
for (int i = 0; i < self.itemCount; i++)
|
||||
{
|
||||
UILabel *label = [self.labels objectAtIndex:i];
|
||||
|
||||
if (i < textField.text.length) {
|
||||
label.text = [textField.text substringWithRange:NSMakeRange(i, 1)];
|
||||
} else {
|
||||
label.text = nil;
|
||||
}
|
||||
}
|
||||
|
||||
[self cursor];
|
||||
|
||||
// 输入完毕后,自动隐藏键盘
|
||||
if (textField.text.length >= self.itemCount) {
|
||||
[self.currentLabel stopAnimating];
|
||||
[textField resignFirstResponder];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)clickMaskView
|
||||
{
|
||||
[self.textField becomeFirstResponder];
|
||||
[self cursor];
|
||||
}
|
||||
|
||||
- (BOOL)endEditing:(BOOL)force
|
||||
{
|
||||
[self.textField endEditing:force];
|
||||
[self.currentLabel stopAnimating];
|
||||
return [super endEditing:force];
|
||||
}
|
||||
|
||||
#pragma mark - 处理光标
|
||||
- (void)cursor
|
||||
{
|
||||
[self.currentLabel stopAnimating];
|
||||
|
||||
NSInteger index = self.code.length;
|
||||
if (index < 0) index = 0;
|
||||
if (index >= self.labels.count) index = self.labels.count - 1;
|
||||
|
||||
HWCursorLabel *label = [self.labels objectAtIndex:index];
|
||||
|
||||
[label startAnimating];
|
||||
self.currentLabel = label;
|
||||
}
|
||||
|
||||
- (NSString *)code
|
||||
{
|
||||
return self.textField.text;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// -----------------------------HWCursorLabel------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
|
||||
@implementation HWCursorLabel
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self setupView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super initWithCoder:coder];
|
||||
if (self) {
|
||||
[self setupView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - 初始化View
|
||||
- (void)setupView
|
||||
{
|
||||
UIView *cursorView = [[UIView alloc] init];
|
||||
cursorView.backgroundColor = [UIColor blueColor];
|
||||
cursorView.alpha = 0;
|
||||
[self addSubview:cursorView];
|
||||
_cursorView = cursorView;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
[super layoutSubviews];
|
||||
|
||||
CGFloat h = 30;
|
||||
CGFloat w = 2;
|
||||
CGFloat x = self.bounds.size.width * 0.5;
|
||||
CGFloat y = self.bounds.size.height * 0.5;
|
||||
self.cursorView.frame = CGRectMake(0, 0, w, h);
|
||||
self.cursorView.center = CGPointMake(x, y);
|
||||
}
|
||||
|
||||
- (void)startAnimating
|
||||
{
|
||||
if (self.text.length > 0) return;
|
||||
|
||||
CABasicAnimation *oa = [CABasicAnimation animationWithKeyPath:@"opacity"];
|
||||
oa.fromValue = [NSNumber numberWithFloat:0];
|
||||
oa.toValue = [NSNumber numberWithFloat:1];
|
||||
oa.duration = 1;
|
||||
oa.repeatCount = MAXFLOAT;
|
||||
oa.removedOnCompletion = NO;
|
||||
oa.fillMode = kCAFillModeForwards;
|
||||
oa.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
|
||||
[self.cursorView.layer addAnimation:oa forKey:@"opacity"];
|
||||
}
|
||||
|
||||
- (void)stopAnimating
|
||||
{
|
||||
[self.cursorView.layer removeAnimationForKey:@"opacity"];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -7,6 +7,13 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
// 屏幕宽度高度
|
||||
#define SW ([UIScreen mainScreen].bounds.size.width)
|
||||
#define SH ([UIScreen mainScreen].bounds.size.height)
|
||||
|
||||
// 随机色
|
||||
#define HWRandomColor [UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1.0]
|
||||
|
||||
@interface ViewController : UIViewController
|
||||
|
||||
|
||||
|
||||
@@ -7,18 +7,18 @@
|
||||
|
||||
#import "ViewController.h"
|
||||
|
||||
#import "HWTFCodeView.h"
|
||||
#import "HWTFCodeBView.h"
|
||||
#import "HWTextCodeView.h"
|
||||
|
||||
// ----------------------------View----------------------------
|
||||
#import "HWTFCodeView.h" // 基础版 - 下划线
|
||||
#import "HWTFCodeBView.h" // 基础版 - 方块
|
||||
#import "HWTextCodeView.h" // 完善版 - 加入动画 - 下划线
|
||||
#import "HWTFCursorView.h" // 基础版 - 下划线 - 有光标
|
||||
|
||||
@interface ViewController ()
|
||||
|
||||
@property (nonatomic, weak) HWTFCodeView *code1View;
|
||||
|
||||
@property (nonatomic, weak) HWTFCodeBView *code2View;
|
||||
|
||||
@property (nonatomic, weak) HWTFCodeView *code1View;
|
||||
@property (nonatomic, weak) HWTFCodeBView *code2View;
|
||||
@property (nonatomic, weak) HWTextCodeView *code3View;
|
||||
@property (nonatomic, weak) HWTFCursorView *code4View;
|
||||
|
||||
@end
|
||||
|
||||
@@ -28,71 +28,103 @@
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
UIScrollView *scrollView = [[UIScrollView alloc] init];
|
||||
scrollView.contentSize = CGSizeMake(SW, SH * 1.5);
|
||||
scrollView.layer.borderColor = [HWRandomColor CGColor];
|
||||
scrollView.layer.borderWidth = 0.5;
|
||||
scrollView.frame = CGRectMake(0, 0, SW, SH);
|
||||
[self.view addSubview:scrollView];
|
||||
|
||||
UILabel *labx = [UILabel new];
|
||||
labx.textColor = [UIColor grayColor];
|
||||
labx.font = [UIFont systemFontOfSize:16];
|
||||
labx.text = @"😘页面可滑动,防止键盘挡住效果😘";
|
||||
labx.frame = CGRectMake(30, 45, 320, 15);
|
||||
[scrollView addSubview:labx];
|
||||
|
||||
|
||||
|
||||
CGFloat x = 30;
|
||||
CGFloat w = self.view.bounds.size.width - x * 2;
|
||||
CGFloat w = SW - x * 2;
|
||||
CGFloat h = 50;
|
||||
CGFloat y = 100;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
UILabel *labA = [UILabel new];
|
||||
labA.hidden = YES;
|
||||
labA.textColor = [UIColor orangeColor];
|
||||
labA.font = [UIFont systemFontOfSize:13];
|
||||
labA.text = @"基本实现原理 - 下划线";
|
||||
labA.frame = CGRectMake(x, y, 200, 15);
|
||||
[self.view addSubview:labA];
|
||||
[scrollView addSubview:labA];
|
||||
|
||||
y = CGRectGetMaxY(labA.frame) + 10;
|
||||
|
||||
HWTFCodeView *code1View = [[HWTFCodeView alloc] initWithCount:6 margin:20];
|
||||
code1View.frame = CGRectMake(x, y, w, h);
|
||||
[self.view addSubview:code1View];
|
||||
[scrollView addSubview:code1View];
|
||||
self.code1View = code1View;
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
y = CGRectGetMaxY(code1View.frame) + 80;
|
||||
y = CGRectGetMaxY(code1View.frame) + 60;
|
||||
|
||||
UILabel *labB = [UILabel new];
|
||||
labB.textColor = [UIColor orangeColor];
|
||||
labB.font = [UIFont systemFontOfSize:13];
|
||||
labB.text = @"基本实现原理 - 方块";
|
||||
labB.frame = CGRectMake(x, y, 200, 15);
|
||||
[self.view addSubview:labB];
|
||||
[scrollView addSubview:labB];
|
||||
|
||||
y = CGRectGetMaxY(labB.frame) + 30;
|
||||
|
||||
HWTFCodeBView *code2View = [[HWTFCodeBView alloc] initWithCount:6 margin:20];
|
||||
code2View.frame = CGRectMake(x, y, w, h);
|
||||
[self.view addSubview:code2View];
|
||||
[scrollView addSubview:code2View];
|
||||
self.code2View = code2View;
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
y = CGRectGetMaxY(code2View.frame) + 80;
|
||||
y = CGRectGetMaxY(code2View.frame) + 60;
|
||||
|
||||
UILabel *labC = [UILabel new];
|
||||
labC.textColor = [UIColor orangeColor];
|
||||
labC.font = [UIFont systemFontOfSize:13];
|
||||
labC.text = @"完善版 - 加入动画 - 下划线";
|
||||
labC.frame = CGRectMake(x, y, 200, 15);
|
||||
[self.view addSubview:labC];
|
||||
[scrollView addSubview:labC];
|
||||
|
||||
y = CGRectGetMaxY(labC.frame) + 30;
|
||||
|
||||
HWTextCodeView *code3View = [[HWTextCodeView alloc] initWithCount:6 margin:20];
|
||||
code3View.frame = CGRectMake(x, y, w, h);
|
||||
[self.view addSubview:code3View];
|
||||
[scrollView addSubview:code3View];
|
||||
self.code3View = code3View;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
y = CGRectGetMaxY(code3View.frame) + 60;
|
||||
|
||||
UILabel *labD = [UILabel new];
|
||||
labD.textColor = [UIColor blueColor];
|
||||
labD.font = [UIFont systemFontOfSize:13];
|
||||
labD.text = @"基础版 - 下划线 - 有光标";
|
||||
labD.frame = CGRectMake(x, y, 200, 15);
|
||||
[scrollView addSubview:labD];
|
||||
|
||||
y = CGRectGetMaxY(labD.frame) + 30;
|
||||
|
||||
HWTFCursorView *code4View = [[HWTFCursorView alloc] initWithCount:6 margin:20];
|
||||
code4View.frame = CGRectMake(x, y, w, h);
|
||||
[scrollView addSubview:code4View];
|
||||
self.code4View = code4View;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap)];
|
||||
[self.view addGestureRecognizer:tap];
|
||||
[scrollView addGestureRecognizer:tap];
|
||||
}
|
||||
|
||||
|
||||
@@ -101,6 +133,7 @@
|
||||
[self.code1View endEditing:YES];
|
||||
[self.code2View endEditing:YES];
|
||||
[self.code3View endEditing:YES];
|
||||
[self.code4View endEditing:YES];
|
||||
}
|
||||
|
||||
|
||||
|
||||
129
README.md
129
README.md
@@ -3,11 +3,134 @@
|
||||
## iOS验证码输入
|
||||
|
||||
> * Xcode 10.0 (10A255) 新建项目并编辑
|
||||
> * 代码日期:2018年09月26日12:30
|
||||
> * 代码日期:2018年12月14日15:00
|
||||
> * 代码语言:Objective-C
|
||||
> * 加入光标小Demo(2018年12月14日)
|
||||
|
||||

|
||||

|
||||
|
||||
简书地址:[点我](https://www.jianshu.com/)
|
||||
简书地址:[点我](https://www.jianshu.com/p/23f7be3677be)
|
||||
简书地址:[点我](https://www.jianshu.com/p/23f7be3677be)
|
||||
|
||||
|
||||
----
|
||||
|
||||
## 博客内容
|
||||
|
||||

|
||||
|
||||
如图所示,现在很多App采用了类似下划线、方块等方式的验证码输入,直观美观!对于这种效果的实现方式,大概有以下几种方式:
|
||||
##### 1.多个`UITextField`组成
|
||||
这种方式好处是有光标闪烁、但是在处理删除和动画效果时,就会显得有点笨拙,OFO应该是这样实现的,要严格处理好每个`UITextField`的`FirstResponder`。
|
||||
##### 2.一个`UITextField`组成,使用富文本
|
||||
这个方式是可行的, 使用富文本设置每个字符的间距,允许编辑富文本,有光标闪烁,缺点应该也是不好处理动画效果。
|
||||
##### 3.使用`UIView`绘制
|
||||
这个是我在`GitHub`上看到的一个半成品Demo,利用一个`UIView`,使用`Quartz 2D`和`UIBezierPath`进行绘制文本和下划线,并处理输入事件和键盘事件,其实整体下来代码也不多,300行以内,但是需要较好的iOS绘制功底。
|
||||
##### 4.一个`UITextField`和多个`UILabel`
|
||||
这个是我接下来介绍的思路,这个思路的缺点应该是没有光标闪烁,其实也能伪实现,看是否必须要有这个需要了。这个思路比较简单,方便加入动画,纯粹下来就100多行,接下来看结构和代码:
|
||||

|
||||
|
||||
新建一个`UIView`,初始化方法
|
||||
```
|
||||
- (instancetype)initWithCount:(NSInteger)count margin:(CGFloat)margin
|
||||
{
|
||||
if (self = [super init]) {
|
||||
self.itemCount = count; // itemCount是验证码的个数,比如6个
|
||||
self.itemMargin = margin; // itemMargin是每个Label之间的间距
|
||||
[self configTextField];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
```
|
||||
添加内部子控件(演示)
|
||||
```
|
||||
- (void)configTextField
|
||||
{
|
||||
UITextField *textField = [[UITextField alloc] init];
|
||||
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
||||
textField.keyboardType = UIKeyboardTypeNumberPad;
|
||||
[textField addTarget:self action:@selector(tfEditingChanged:) forControlEvents:(UIControlEventEditingChanged)];
|
||||
|
||||
// 小技巧:这个属性为YES,可以强制使用系统的数字键盘,缺点是重新输入时,会清空之前的内容
|
||||
// clearsOnBeginEditing 属性并不适用于 secureTextEntry = YES 时
|
||||
// textField.secureTextEntry = YES;
|
||||
|
||||
[self addSubview:textField];
|
||||
self.textField = textField;
|
||||
|
||||
// 小技巧:通过textField上层覆盖一个maskView,可以去掉textField的长按事件
|
||||
UIButton *maskView = [UIButton new];
|
||||
maskView.backgroundColor = [UIColor whiteColor];
|
||||
[maskView addTarget:self action:@selector(clickMaskView) forControlEvents:(UIControlEventTouchUpInside)];
|
||||
[self addSubview:maskView];
|
||||
self.maskView = maskView;
|
||||
|
||||
for (NSInteger i = 0; i < self.itemCount; i++)
|
||||
{
|
||||
UILabel *label = [UILabel new];
|
||||
[self addSubview:label];
|
||||
[self.labels addObject:label];
|
||||
}
|
||||
|
||||
for (NSInteger i = 0; i < self.itemCount; i++)
|
||||
{
|
||||
UIView *line = [UIView new];
|
||||
[self.lines addObject:line];
|
||||
}
|
||||
}
|
||||
```
|
||||
这里可能对`maskView `有点费解,`maskView`主要是为了挡住下面的`UITextField `,使用类`UIButton `是为了挡住事件,因为如果使用类`UIView `,会将事件传递到`self`,进而影响到外面隐藏键盘的代码,你可以试试就知道了。
|
||||
|
||||
##### 主要处理业务逻辑的代码
|
||||
|
||||
```
|
||||
#pragma mark - 编辑改变
|
||||
- (void)tfEditingChanged:(UITextField *)textField
|
||||
{
|
||||
if (textField.text.length > self.itemCount) {
|
||||
textField.text = [textField.text substringWithRange:NSMakeRange(0, self.itemCount)];
|
||||
}
|
||||
|
||||
for (int i = 0; i < self.itemCount; i++)
|
||||
{
|
||||
UILabel *label = [self.labels objectAtIndex:i];
|
||||
|
||||
if (i < textField.text.length) {
|
||||
label.text = [textField.text substringWithRange:NSMakeRange(i, 1)];
|
||||
} else {
|
||||
label.text = nil;
|
||||
}
|
||||
}
|
||||
|
||||
// 输入完毕后,自动隐藏键盘
|
||||
if (textField.text.length >= self.itemCount) {
|
||||
[textField resignFirstResponder];
|
||||
}
|
||||
}
|
||||
```
|
||||
这里没有使用`UITextField `的`delegate`,使用`UIControlEventEditingChanged`足以,但是如果你的需求能输入英文等其他字符,就需要实现`delegate`去限制。
|
||||
|
||||
至此,验证码输入的核心代码就***没有了***,是不是感觉这么少!!在此基础上,我用Demo实现了3个基本效果,如图所示:
|
||||
|
||||

|
||||
|
||||
#### Github代码地址:[点我](https://github.com/HouWan/CodeTextDemo)
|
||||
|
||||
#####小技巧Tip
|
||||
当你不想让别人使用某个方法时,除了私有方法办法之外,还可以这么做:
|
||||
```
|
||||
- (instancetype)init UNAVAILABLE_ATTRIBUTE;
|
||||
+ (instancetype)new UNAVAILABLE_ATTRIBUTE;
|
||||
```
|
||||
|
||||
|
||||
## 有问题反馈
|
||||
如果大家在使用过程中遇到其他问题,可以留言,我们共同解决。
|
||||
|
||||
**PS**:最近我有跳槽的想法,有工作机会的老板,欢迎骚扰哦!北京呦!
|
||||
|
||||
**END。**
|
||||
*我是小侯爷。*
|
||||
*在魔都艰苦奋斗,白天是上班族,晚上是知识服务工作者。*
|
||||
*如果读完觉得有收获的话,记得关注和点赞哦。*
|
||||
*非要打赏的话,我也是不会拒绝的。*
|
||||
|
||||
BIN
Screen.png
Normal file
BIN
Screen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB |
Reference in New Issue
Block a user