说实话,本人一直不喜欢手势密码,可是偏偏经常遇到手势密码;我们自己做的APP的手势密码逻辑超级复杂,都感觉有心里阴影了。
这次的第一个任务就是解有关手势密码的Bug,真是怕什么来什么。
不过怕也没有用,只能硬着头皮上。登录进去后感觉了一下,还好,逻辑比较简单清晰,问题也比较明显,可以尝试一下。
问题:

代码位置

检查位置
从Bug的描述来看,需求改动是在第2次绘制结束时就自动判断,不需要等到按下确定按钮了。
XLGestureLockView就有绘制结束的回调函数,这里是以协议和代理的方式给出的:
@protocol XLGestureLockDelegate <NSObject>
- (void)gestureLockView:(XLGestureLockView *)lockView drawRectFinished:(NSMutableString *)gesturePassword;
@end
再看使用文件XLGestureLockVC
,原来就有这方面的逻辑:
#pragma mark - XLGestureLockDelegate
- (void)gestureLockView:(XLGestureLockView *)lockView drawRectFinished:(NSMutableString *)gesturePassword {
if (gesturePassword.length < 4) {
_titleLB.text = @"至少连接四个点,请重新输入";
[self shakeAnimationForView:_titleLB];
[lockView clearLockView];
return;
}
XLLog(@"当前绘制密码%@", gesturePassword);
if (self.type == XLGestureLockVCFromTypeSetting) {
if (self.nextStep == 1) {//第一次输入数字密码
_titleLB.text = @"请再次绘制手势";
self.nextStep = 2;
self.lastPS = gesturePassword;
[lockView clearLockView];
} else {//第二次输入数字密码
self.currentPS = gesturePassword;
[self autoCheckPS];
}
} else {
NSString *savePS = [XLUserDefaults getLastGesturePassword];
if (self.nextStep == 1) {//校验密码
if ([savePS isEqualToString:gesturePassword]) {
self.nextStep = 2;
_titleLB.text = @"请绘制新的手势";
[lockView clearLockView];
} else {
_titleLB.text = @"手势校验错误";
[self shakeAnimationForView:_titleLB];
[lockView clearLockView];
}
} else if (self.nextStep == 2) {
_titleLB.text = @"请再次绘制手势";
self.nextStep = 3;
self.lastPS = gesturePassword;
[lockView clearLockView];
} else {
self.currentPS = gesturePassword;
[self autoCheckPS];
}
}
}
原来的第2次输入只有保存输入的密码,其他什么也没做:
self.currentPS = gesturePassword;
// 下面就什么也没有了
如何修改?
由于有设置手势密码和修改手势密码两个地方用到,所以就集中写了一个方法,防止重复。
// 自动检查前后两次手势密码是否一致
- (void)autoCheckPS {
// 如果查出不一致,就toast提示;并清除(相当于按了重新输入按钮); 并晃动
if (![self.lastPS isEqualToString:self.currentPS]) {
[self clickAgainDraw];
[XLToast showErrorMessage:@"前后手势不一致!"];
_titleLB.text = @"前后手势不一致!请重新输入";
[self shakeAnimationForView:_titleLB];
} else {
_titleLB.text = @"请点击确认按钮";
}
}
-
原来的重新输入就是清除,并且根据情况清除缓存的输入,原来就有的逻辑,不改,直接调用;
-
Toast提示文字在确认按钮之后就有,不用改,直接照抄;
-
按钮晃动和文字信息原文中有,照搬;
这样基本上复用了原来的逻辑,改动最小,最集中,也实现了需求。
如何实现动画?
这里用了一个动画,左右抖动距离为10,可以借鉴:
// 抖动动画
- (void)shakeAnimationForView:(UIView *)view {
CALayer *viewLayer = view.layer;
CGPoint position = viewLayer.position;
CGPoint left = CGPointMake(position.x - 10, position.y);
CGPoint right = CGPointMake(position.x + 10, position.y);
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[animation setFromValue:[NSValue valueWithCGPoint:left]];
[animation setToValue:[NSValue valueWithCGPoint:right]];
[animation setAutoreverses:YES]; // 平滑结束
[animation setDuration:0.08];
[animation setRepeatCount:3];
[viewLayer addAnimation:animation forKey:nil];
}
手势密码视图
这个是一个简配版的手势密码视图:
原理是排了9个UIButton,通过设置UIButton的image来展示手势。
密码的创建就是for循环0到8;密码的数字就是UIButton的tag=i+1;也就是1到9;
密码视图的实现大同小异,第一个想出来的人很厉害,后面的基本上是小改动。
手势移动的线就是按钮中心的直线连接;
// 只要调用这个方法就会把之前绘制的东西清空 重新绘制
- (void)drawRect:(CGRect)rect {
if (_selectBtns.count == 0) return;
// 把所有选中按钮中心点连线
UIBezierPath *path = [UIBezierPath bezierPath];
for (int i = 0; i < self.selectBtns.count; i ++) {
UIButton *btn = self.selectBtns[i];
if (i == 0) {
[path moveToPoint:btn.center]; // 设置起点
} else {
[path addLineToPoint:btn.center];
}
}
//判断是否松开手指
if (self.finished) {
//松开手
NSMutableString *pwd = [self transferGestureResult];//传递创建的密码
[[UIColor colorWithRed:94/255.0 green:195/255.0 blue:49/255.0 alpha:0.8] set];
if ([self.delegate respondsToSelector:@selector(gestureLockView:drawRectFinished:)]) {
[self.delegate gestureLockView:self drawRectFinished:pwd];
}
switch (self.resultType) {
case ResultKindTypeTrue:
{
//正确
[[UIColor clearColor] set];
}
break;
case ResultKindTypeFalse:
{
//错误
[[UIColor redColor] set];
for (int i = 0; i < self.errorBtns.count; i++) {
UIButton *btn = [self.errorBtns objectAtIndex:i];
[btn setImage:[UIImage imageNamed:@"ssred"] forState:UIControlStateNormal];
}
break;
case ResultKindTypeNoEnough:
{
[[UIColor clearColor] set];
}
break;
case ResultKindTypeClear:
{
}
break;
default:
break;
}
}
} else {
[path addLineToPoint:self.currentPoint];
[[UIColor orangeColor] set];
}
// 设置路径属性
path.lineWidth = 6;
path.lineJoinStyle = kCGLineCapRound;
path.lineCapStyle = kCGLineCapRound;
// 渲染
[path stroke];
}
网友评论