手势解锁这样的例子网上很多。对于新手而言,如果对iOS不是很熟悉,做这样的功能有一种无从下手的感觉,主要是因为某些细节看起来不好实现。我平时在开发项目的时候,一般遵循一个原则就是,先详细分析,把整个逻辑理清楚,先不管看起来多么难,一个一个的细节剥离开来,然后开始构思,最好是越简单越好,条理性越清楚越好。我最初学习iOS的时候,当时很想做一个手势解锁这样的功能,但是因为当时对iOS开发不熟悉,尝试了很多复杂的方式,但是总是不是很完美。现在就采用一种简单地方式来实现一个手势解锁组件。这是我目前想到的最简单的方法。
先看一下具体的效果图:
下面我先详细分析一下,具体的实现方式:
1.实现3行3列排布圆形,每个圆之间的间距相等,总体摆匀称就行了(这里涉及到一些坐标运算)。
2.截获用户手指在屏幕上滑动的事件,然后根据滑动的具体坐标绘制折线(请允许我把这些连接起来的线称为折线)。
3.触摸手指离开屏幕时,清除所有的绘制图案。
这里有个比较棘手的细节不好处理,简单归纳如下:
如果某个点已经被连过,那么下次再次移动到此点上的时候,不能再重复连线。
现在我们开始分析前面所述的三个步骤如何实现:
1.这里的圆形,我们观察到,有两种状态,一种是发光的,一种是不发光的。我最初刚开始看到这样的效果的效果的时候,我直观的使用绘图的方式绘制了9个圆形,但这样思考问题的时候,很显然感觉到异常复杂,仅仅是处理圆形的两种状态就已经很让人头痛了。这里,我们直接创建9个按钮,然后设置不同状态的图片即可。所以我们在初始化方法里面创建9个button,并添加到父视图。这里最好对按钮做一些封装,屏蔽一些细节,让总体的代码更加简洁。这里我继承UIButton类,实现了一个名为HGCircleView的类。在后面创建的时候,我们直接引用这个类:
\\在initWithFrame方法里面实现如下的代码 创建圆形
for (NSUInteger i = 0; i < COL_COUNT * ROW_COUNT; ++i) {
HGCircleView* circleView = [HGCircleView circleView];
[self addSubview:circleView];
}
2.主要的逻辑就在于第2步了,当用户在屏幕上移动触摸点的时候,我们要追踪到移动的轨迹,然后绘制折线。
首先,要追踪用户触摸的轨迹,我们需要重写三个方法:
touchesBegan、touchesMoved、touchesEnded
这三个方法里面我们可以记录下用户最初按压时的点,移动过程中的当前点,以及手指离开时的点。
在这里,先不要急于绘制移动的路径。最终的目的是要把所有触摸轨迹经过的圆形串起来并生成密码。所以我在这里用一个容器,保存了路径经过的所有的circleView。这里处理一个细节就是,当触摸到圆形的时候,我们设置圆形的状态是selected.并在circleView类的内部设置好selected状态下,显示发光效果的图片。
这里顺便就可以处理前面提到的那个比较棘手的细节,在手势经过圆形的时候,先做一个检查,如果发现圆形已经处于selected状态,那么,就不在把圆形加入容器,这样就不会重复选择,很轻松就解决了那个问题。
接下来,在drawRect方法里面绘制触摸轨迹,遍历容器,然后把所有的圆形的center加入UIBezierPath,然后绘制UIBezierPath即可。
这样会出现一个新的问题,就是,当触摸移动到其他位置(不在圆形上),这个时候,不能同步绘制,这里我采取的处理方式是,用一个点记录当前用户手指触摸移动的位置,然后把这个点作为最后一个点加入到UIBezierPath中,为了保证这个点的可靠性,在每次按压屏幕的时候将这个点置为(-10, -10),并且在添加到UIBezierPath路径之前检查一下,如果不是(-10, -10)则加入路径。
// 1.容器为空,不执行任何绘制
if (0 == self.circleViews.count) {
return;
}
UIBezierPath* bezierPath = [UIBezierPath new];
[bezierPath moveToPoint: [[self.circleViews firstObject] center]];
for (NSUInteger i = 1; i < self.circleViews.count; ++i) {
[bezierPath addLineToPoint:[[self.circleViews objectAtIndex:i] center]];
}
if (NO == CGPointEqualToPoint(self.curlastPoint, CGPointMake(-10.0f, -10.0f))) {
[bezierPath addLineToPoint:self.curlastPoint];
}
// 2.设置线形
bezierPath.lineWidth = 7;
bezierPath.lineJoinStyle = kCGLineJoinBevel;
[[UIColor colorWithRed:36/255.0 green:200/255.0 blue:260/255.0 alpha:0.5] set];// 3.绘制路径
[bezierPath stroke];
3.手指触摸弹起来的时候,需要清空绘制,这个时候,这需要清空保存所有被选择circleView的容器即可。注意在清空之前,应该先利用容器内的圆形的相关信息生成密码。并且把所有圆形的状态置为Normal状态。
上述这些步骤即可以完成一个手势解锁功能。好了,说了半天,也没有用上手势识别器,仅仅处理了三个事件。你可以下载详细代码参考。
详细代码实现github地址:点击这里下载