这次支付宝手机客户端升级,把手势解锁那个功能去掉了,引起很多人的抱怨,觉得少了手势解锁的保护,个人信息容易泄漏了。。。
那么手势解锁功能是怎么是实现的呢,这里使用Quart2D来简单模拟一下,
先看下截图效果:
按钮的有两个背景图片,一个默认样式,一个用于选中样式:
代码实现:
自定义view, 用来绘制所有路径,自定义view名称为:GestureLockView
GestureLockView.h文件:
#import <UIKit/UIKit.h> @interface GestureLockView : UIView @end
GestureLockView.m文件代码:
1 // 手势解锁 2 3 #import "GestureLockView.h" 4 5 @interface GestureLockView() 6 7 @property (nonatomic, retain) NSMutableArray *selectBtns; 8 @property (nonatomic, assign) CGPoint moveP; //移动的点 9 10 @end 11 12 @implementation GestureLockView 13 14 - (instancetype)initWithFrame:(CGRect)frame{ 15 if (self = [super initWithFrame:frame]){ 16 [self addBtns]; 17 NSLog(@"initWithFrame: %s", __func__); 18 } 19 return self; 20 } 21 22 //解析xib的时候调用 23 - (instancetype)initWithCoder:(NSCoder *)aDecoder{ 24 if (self = [super initWithCoder:aDecoder]){ 25 NSLog(@"initWithCoder: %s", __func__); 26 [self addBtns]; 27 } 28 return self; 29 } 30 31 //添加子按钮 32 - (void)addBtns{ 33 for (int i = 0; i < 9; i++) { 34 UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; 35 [btn setBackgroundImage:[UIImage imageNamed:@"gesture_node_normal"] forState:UIControlStateNormal]; 36 [btn setBackgroundImage:[UIImage imageNamed:@"gesture_node_highlighted"] forState:UIControlStateSelected]; 37 [btn setUserInteractionEnabled:NO]; //设置不能和用户进行交互 38 [btn setTag:i + 1]; //设置标识 39 [self addSubview:btn]; 40 } 41 } 42 43 - (NSMutableArray *)selectBtns{ 44 if (_selectBtns == nil){ 45 _selectBtns = [[NSMutableArray alloc] init]; 46 } 47 return _selectBtns; 48 } 49 50 //触摸开始 51 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ 52 NSLog(@"触摸开始..."); 53 54 self.moveP = [self getPoint:touches]; 55 UIButton *btn = [self getBtn:self.moveP]; 56 57 if (btn != nil){ 58 [self.selectBtns addObject:btn]; 59 btn.selected = YES; 60 } 61 } 62 63 //触摸移动, 设置被选中的按钮 64 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ 65 //NSLog(@"触摸移动"); 66 self.moveP = [self getPoint:touches]; 67 UIButton *btn = [self getBtn:self.moveP]; 68 69 if (btn != nil && btn.selected == NO){ 70 [self.selectBtns addObject:btn]; 71 btn.selected = YES; 72 } 73 74 [self setNeedsDisplay]; //从新绘制 75 } 76 77 //触摸结束,一切归空 78 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ 79 NSMutableString *str = [[NSMutableString alloc] init]; 80 for (UIButton * btn in self.selectBtns) { 81 [str appendFormat:@"%i", btn.tag]; 82 btn.selected = NO; 83 } 84 85 self.moveP = CGPointZero; 86 [self setNeedsDisplay]; 87 [self.selectBtns removeAllObjects]; 88 89 // UILabel *lbl = [[UILabel alloc] init]; 90 // lbl.text = [NSString stringWithFormat:@"密码是:%@", str]; 91 // lbl.frame = CGRectMake(80, 150, 200, 30); 92 // [lbl setBackgroundColor:[UIColor whiteColor]]; 93 // [lbl setTextAlignment:NSTextAlignmentCenter]; 94 // [self addSubview:lbl]; 95 // 96 // [UIView animateWithDuration:5.0 animations:^{ 97 // lbl.alpha = 0.1; 98 // } completion:^(BOOL finished) { 99 // [lbl removeFromSuperview]; 100 // }]; 101 102 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"设置结果为" message:str delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil, nil]; 103 [alert show]; 104 } 105 106 //监听触摸移动,获取触摸坐标 107 - (CGPoint)getPoint: (NSSet *)touches{ 108 UITouch *touch = [touches anyObject]; //获取当前接触点 109 return [touch locationInView:self]; //获取当前触点在父对象中的位置 110 } 111 112 //根据坐标获取按钮对象 113 - (UIButton *)getBtn: (CGPoint)point{ 114 for (UIButton * btn in self.subviews) { 115 if (CGRectContainsPoint(btn.frame, point)){ 116 return btn; 117 } 118 } 119 return nil; 120 } 121 122 //布局子控件的坐标位置 123 - (void)layoutSubviews{ 124 CGFloat width = 74; 125 CGFloat height = width; 126 CGFloat cols = 3; 127 CGFloat rows = cols; 128 CGFloat margin = ([UIScreen mainScreen].bounds.size.width - width * cols) / (cols + 1); 129 130 for (int i = 0; i < rows; i++) { 131 for (int j = 0; j < cols; j++) { 132 CGFloat x = j * (width + margin) + margin; 133 CGFloat y = i * (height + margin) + margin; 134 UIButton *btn = (UIButton *)[self.subviews objectAtIndex: (i * rows) + j]; 135 btn.frame = CGRectMake(x, y, width, height); 136 } 137 } 138 } 139 140 141 // 142 // Only override drawRect: if you perform custom drawing. 143 // An empty implementation adversely affects performance during animation. 144 //从新绘制 145 - (void)drawRect:(CGRect)rect { 146 //1、获取当前上下文 147 CGContextRef ctr = UIGraphicsGetCurrentContext(); 148 //2、绘制路径 149 UIBezierPath *path = [UIBezierPath bezierPath]; 150 CGContextSetLineWidth(ctr, 8); //设置线段宽度 151 CGContextSetLineJoin(ctr, kCGLineJoinRound); //设置转折点 152 [[UIColor whiteColor] set]; //设置路径颜色 153 154 [path moveToPoint:self.moveP]; 155 156 for (int i = 0; i < self.selectBtns.count; i++) { 157 UIButton *btn = (UIButton *)[self.selectBtns objectAtIndex:i]; 158 CGPoint point = btn.center; 159 160 if (i == 0){ 161 [path moveToPoint:point]; 162 } 163 else{ 164 [path addLineToPoint:point]; 165 } 166 } 167 168 if (!CGPointEqualToPoint(self.moveP, CGPointZero)){ 169 [path addLineToPoint:self.moveP]; //重点路径 170 } 171 //3、把路径添加到上下文中 172 CGContextAddPath(ctr, path.CGPath); 173 174 //4、渲染 175 CGContextStrokePath(ctr); 176 } 177 178 179 @end
自定义控制器来展示自定义手势解锁view
GestureLockViewController.h :
#import <UIKit/UIKit.h> @interface GestureLockViewController : UIViewController @end
GestureLockViewController.m文件代码:
1 #import "GestureLockViewController.h" 2 #import "GestureLockView.h" 3 4 @interface GestureLockViewController () 5 6 @end 7 8 @implementation GestureLockViewController 9 10 - (void)viewDidLoad { 11 [super viewDidLoad]; 12 // Do any additional setup after loading the view. 13 [self.view setBackgroundColor:[UIColor whiteColor]]; 14 15 //返回按钮 16 UIButton *preBtn = [UIButton buttonWithType:UIButtonTypeCustom]; 17 [preBtn setFrame:CGRectMake(10, 420, 80, 25)]; 18 [preBtn setBackgroundColor:[UIColor purpleColor]]; 19 [preBtn setTitle:@"返回" forState:UIControlStateNormal]; 20 [preBtn addTarget:self action:@selector(prePage) forControlEvents:UIControlEventTouchUpInside]; 21 [self.view addSubview:preBtn]; 22 23 //增加view 24 CGSize size = [UIScreen mainScreen].bounds.size; 25 GestureLockView *view = [[GestureLockView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.width + 30)]; 26 [view setBackgroundColor:[UIColor blackColor]]; 27 [self.view addSubview:view]; 28 } 29 30 - (void)prePage{ 31 [self dismissViewControllerAnimated:YES completion:nil]; 32 } 33 34 - (void)didReceiveMemoryWarning { 35 [super didReceiveMemoryWarning]; 36 // Dispose of any resources that can be recreated. 37 } 38 39 /* 40 #pragma mark - Navigation 41 42 // In a storyboard-based application, you will often want to do a little preparation before navigation 43 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 44 // Get the new view controller using [segue destinationViewController]. 45 // Pass the selected object to the new view controller. 46 } 47 */ 48 49 @end