这次支付宝手机客户端升级,把手势解锁那个功能去掉了,引起很多人的抱怨,觉得少了手势解锁的保护,个人信息容易泄漏了。。。
那么手势解锁功能是怎么是实现的呢,这里使用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