手势密码的使用:
手势密码构造的核心思想是绘图,主要问题为一下四个问题
一:移动起始点到移动末端的处理(如何绘图)
二:非绘图点为起始点如何处理
三:是否过关键绘图点(Button or ImageView)
四:如何进行密码的保存
下面我们带着这四个问题开始进行处理手势解锁
touch事件的处理
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
CGPoint touchPoint;
UITouch *touch = [touches anyObject];
[touchesArray removeAllObjects];
[touchedArray removeAllObjects];
// 开始滑动,清空临时密码(上次滑动产生的临时密码)
[touchBeginDelegate gestureTouchBegin];
success=1;
if (touch) {
// touch的坐标点
touchPoint = [touch locationInView:self];
for (int i=0; i<buttonArray.count; i++) {
// 获取关键绘图点(密码点)
GesturePasswordButton * buttonTemp = ((GesturePasswordButton *)[buttonArray objectAtIndex:i]);
[buttonTemp setSuccess:YES];
[buttonTemp setSelected:NO];
// 判断起始点是不是在密码点中
if (CGRectContainsPoint(buttonTemp.frame,touchPoint)) {
CGRect frameTemp = buttonTemp.frame;
// button的中心点
CGPoint point = CGPointMake(frameTemp.origin.x+frameTemp.size.width/2,frameTemp.origin.y+frameTemp.size.height/2);
NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%f",point.x],@"x",[NSString stringWithFormat:@"%f",point.y],@"y", nil];
// 添加触动点
[touchesArray addObject:dict];
// 把触动点做为起始点
lineStartPoint = touchPoint;
}
[buttonTemp setNeedsDisplay];
}
[self setNeedsDisplay];
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
CGPoint touchPoint;
UITouch *touch = [touches anyObject];
if (touch) {
touchPoint = [touch locationInView:self];
for (int i=0; i<buttonArray.count; i++) {
GesturePasswordButton * buttonTemp = ((GesturePasswordButton *)[buttonArray objectAtIndex:i]);
// 判断是否经过密码区域
if (CGRectContainsPoint(buttonTemp.frame,touchPoint)) {
// 判断是否保存过改密码区域编号(密码)
if ([touchedArray containsObject:[NSString stringWithFormat:@"num%d",i]]) {
// 设置为终点
lineEndPoint = touchPoint;
[self setNeedsDisplay];
return;
}
// 添加密码
[touchedArray addObject:[NSString stringWithFormat:@"num%d",i]];
[buttonTemp setSelected:YES];
[buttonTemp setNeedsDisplay];
// 添加密码点到触点列表
CGRect frameTemp = buttonTemp.frame;
CGPoint point = CGPointMake(frameTemp.origin.x+frameTemp.size.width/2,frameTemp.origin.y+frameTemp.size.height/2);
NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%f",point.x],@"x",[NSString stringWithFormat:@"%f",point.y],@"y",[NSString stringWithFormat:@"%d",i],@"num", nil];
[touchesArray addObject:dict];
break;
}
}
// 把移动到的点做为线的终点,用于即时绘图(画线)
lineEndPoint = touchPoint;
[self setNeedsDisplay];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
NSMutableString * resultString=[NSMutableString string];
for ( NSDictionary * num in touchesArray ){
if(![num objectForKey:@"num"])break;
// 生成密码
[resultString appendString:[num objectForKey:@"num"]];
NSLog(@"passward === %@ touchhes == ",num);
}
if(style==1){
// 判断手势密码,进行对应操作
success = [rerificationDelegate verification:resultString];
}
else {
success = [resetDelegate resetPassword:resultString];
}
for (int i=0; i<touchesArray.count; i++) {
NSInteger selection = [[[touchesArray objectAtIndex:i] objectForKey:@"num"]intValue];
GesturePasswordButton * buttonTemp = ((GesturePasswordButton *)[buttonArray objectAtIndex:selection]);
[buttonTemp setSuccess:success];
[buttonTemp setNeedsDisplay];
}
[self setNeedsDisplay];
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
// if (touchesArray.count<2)return;
for (int i=0; i<touchesArray.count; i++) {
CGContextRef context = UIGraphicsGetCurrentContext();
if (![[touchesArray objectAtIndex:i] objectForKey:@"num"]) { //防止过快滑动产生垃圾数据
[touchesArray removeObjectAtIndex:i];
continue;
}
// 画线
if (success) {
CGContextSetRGBStrokeColor(context, 251/255.f, 187/255.f, 20/255.f, 1.0);//金色
}
else {
CGContextSetRGBStrokeColor(context, 251/255.f, 187/255.f, 20/255.f, 1.0);//金色
}
// 线宽
CGContextSetLineWidth(context,5);
// 设置目标线段终点
CGContextMoveToPoint(context, [[[touchesArray objectAtIndex:i] objectForKey:@"x"] floatValue], [[[touchesArray objectAtIndex:i] objectForKey:@"y"] floatValue]);
// 如果不是最后一个密码点
if (i<touchesArray.count-1) {
// 再次连线到下一个密码点
CGContextAddLineToPoint(context, [[[touchesArray objectAtIndex:i+1] objectForKey:@"x"] floatValue],[[[touchesArray objectAtIndex:i+1] objectForKey:@"y"] floatValue]);
}
else{
if (success) {
// 如果是最后一个点,则连线到终点
CGContextAddLineToPoint(context, lineEndPoint.x,lineEndPoint.y);
}
}
CGContextStrokePath(context);
}
}
注意事项:
1、如果最后的连线的位置不是密码点,则取消最后一个密码到手势终点的连线(这一步的完成并不是删除,只是在手势完成之后线段的重新绘制)
2、关于style的说明,手势密码使用过程中的对应状态(可分为验证手势密码和设置手势密码,所以相对应的调用方法)
3、关于success的说明,button的success是在非填充图片的情况下使用的
TentacleView的success是用来相button传递数据的
4、关于button(密码点)可以自定义样式和响应事件,在此不做描述