一行代码搞定iOS手势解锁功能

1、有图有真相

iOS Simulator Screen Shot 2014年12月27日 下午9.46.46

2、设计思路

2.1、以屏幕宽度为边长创建一个正方形View;
2.2、一个for循环创建9个按钮并自动布局;
2.3、监听该view的触摸事件,触摸区域落在某按钮区域则按钮发光
2.4、记录发光的按钮,输出按钮顺序(可以在for循环创建按钮时给按钮做tag标记,这样就有对应关系了,从而把按钮转换成字符串密码)

3、代码示例

SAScreenLockView.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//
//? SAScreenLockView.h
//? SAScreenLock
//
//? Created by 余西安 on 14/12/27.
//? Copyright (c) 2014年 Sian. All rights reserved.
//
?
#import <UIKit/UIKit.h>
?
/***************代理协议***************/
?
@class SAScreenLockView;
?
@protocol SAScreenLockViewDelegate 
?
- (void)screenLock:(SAScreenLockView *)screenLockView didFinishPaht:(NSNumber *)path;
?
@end
?
/***************圆圈控件***************/
?
@interface SACircle : UIButton
?
@end
?
/***************解锁视图***************/
?
@interface SAScreenLockView : UIView
?
@property (nonatomic, weak) id delegate;
?
- (id)initWithDelegate:(id)delegate;
?
@end

SAScreenLockView.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
//
//? SAScreenLockView.m
//? SAScreenLock
//
//? Created by 余西安 on 14/12/27.
//? Copyright (c) 2014年 Sian. All rights reserved.
//
?
#import "SAScreenLockView.h"
?
/*********************圆圈控件*********************/
?
@implementation SACircle
?
- (id)initWithCoder:(NSCoder *)aDecoder
{
????if (self = [super initWithCoder:aDecoder]) {
????????[self setup];
????}
????return self;
}
?
- (id)initWithFrame:(CGRect)frame
{
????self = [super initWithFrame:frame];
????if (self) {
????????[self setup];
????}
????return self;
}
?
- (void)setup
{
????self.userInteractionEnabled = NO;
????UIImage *normal = [UIImage imageNamed:@"gesture_node_normal.png"];
????UIImage *selected = [UIImage imageNamed:@"gesture_node_highlighted"];
????[self setImage:normal forState:UIControlStateNormal];
????[self setImage:selected forState:UIControlStateSelected];
}
@end
?
/*********************解锁视图*********************/
?
@interface SAScreenLockView ()
?
@property (nonatomic, strong) NSMutableArray *circles;
?
@property (nonatomic, assign) CGPoint??????? position;
?
@end
?
@implementation SAScreenLockView
?
#pragma mark - 初始化方法
- (id)initWithDelegate:(id)delegate
{
????if (self = [super init]) {
????????self.delegate = delegate;
????}
????return self;
}
// xib创建时调用
- (id)initWithCoder:(NSCoder *)aDecoder
{
????if (self = [super initWithCoder:aDecoder]) {
????????[self setup];
????}
????return self;
}
// 代码创建时调用
- (id)initWithFrame:(CGRect)frame
{
????self = [super initWithFrame:frame];
????if (self) {
????????[self setup];
????}
????return self;
}
// 初始化9个子控件
- (void)setup
{
????self.backgroundColor = [UIColor clearColor];
????CGFloat width = [[UIScreen mainScreen] bounds].size.width;
????self.frame = (CGRect){CGPointZero, width, width};
????for (int i = 0; i < 9; i++) {
????????SACircle *circle = [SACircle buttonWithType:UIButtonTypeCustom];
????????circle.tag = i + 1;
????????[self addSubview:circle];
????}
}
// 被选中的子控件
- (NSMutableArray *)circles
{
????if (_circles == nil){
????????_circles = [NSMutableArray array];
????}
????return _circles;
}
// 子控件位置调整
- (void)layoutSubviews
{
????NSInteger columns = 3;
????CGFloat width = self.frame.size.width;
????CGFloat dimeter = 64.0f;
????CGFloat margic = (width - dimeter * columns) / (columns + 1);
????for (SACircle *circle in self.subviews) {
????????CGFloat x = (circle.tag - 1) % columns * (dimeter + margic) + margic;
????????CGFloat y = (circle.tag - 1) / columns * (dimeter + margic);
????????CGFloat w = dimeter;
????????CGFloat h = dimeter;
????????circle.frame = (CGRect){x, y, w, h};
????}
????CGRect rect = self.frame;
????rect.size.height = dimeter * 3 + margic * 2;
????self.frame = rect;
}
?
#pragma mark - 触摸交互事件处理
- (CGPoint)pointWithTouch:(NSSet *)touches
{
????UITouch *touch = [touches anyObject];
????return [touch locationInView:self];
}
?
- (SACircle *)circleWithTouches:(NSSet *)touches
{
????CGPoint pos = [self pointWithTouch:touches];
????// 判断当前触摸位置是否进入9个圆圈内
????for (SACircle *circle in self.subviews) {
????????CGRect touchArea = circle.frame;
????????CGFloat w = touchArea.size.width;
????????touchArea.origin.x += w / 4;
????????touchArea.origin.y += w / 4;
????????touchArea.size.width -= w / 2;
????????touchArea.size.height -= w / 2;
????????if (CGRectContainsPoint(touchArea, pos)){
????????????return circle;
????????}
????}
????return nil;
}
?
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
????self.position = CGPointZero;
????SACircle *circle = [self circleWithTouches:touches];
????// 如果进入圆圈内并且当前圆圈未被选中则加入到选中数组
????if (circle && !circle.selected){
????????circle.selected = YES;
????????[self.circles addObject:circle];
????}
????[self setNeedsDisplay];
}
?
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
????self.position = [self pointWithTouch:touches];
????SACircle *circle = [self circleWithTouches:touches];
????// 如果进入圆圈内并且当前圆圈未被选中则加入到选中数组
????if (circle && !circle.selected){
????????circle.selected = YES;
????????[self.circles addObject:circle];
????}
????[self setNeedsDisplay];
}
?
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
????NSMutableString *path = [NSMutableString string];
????for (SACircle *circle in self.circles) {
????????circle.selected = NO;
????????[path appendFormat:@"%d", (int)circle.tag];
????}
????// 当选中的圆圈不为空,并且代理有实现代理方法时通知代理
????if ([self.delegate respondsToSelector:@selector(screenLock:didFinishPaht:)] && self.circles.count)
????????[self.delegate screenLock:self didFinishPaht:@([path longLongValue])];
?????
????[self.circles removeAllObjects];
????[self setNeedsDisplay];
}
?
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
????[self touchesEnded:touches withEvent:event];
}
?
#pragma mark - 视图绘制方法
- (void)drawRect:(CGRect)rect
{
????if (self.circles.count == 0) return;
????UIBezierPath *path = [UIBezierPath bezierPath];
????path.lineWidth = 8;
????path.lineCapStyle = kCGLineCapRound;
????path.lineJoinStyle = kCGLineJoinRound;
????for (int i = 0; i < self.circles.count; i++) {
????????SACircle *circle = self.circles[i];
????????if (i == 0) {
????????????[path moveToPoint:circle.center];
????????} else {
????????????[path addLineToPoint:circle.center];
????????}
????}
????if (!CGPointEqualToPoint(self.position, CGPointZero))
????????[path addLineToPoint:self.position];
????[[UIColor colorWithRed:122/255.0 green:214/255.0 blue:250/255.0 alpha:0.7] set];
????[path stroke];
}
?
@end

4、Demo下载:SAScreenLock

Leave a Reply