这次支付宝手机客户端升级,把手势解锁那个功能去掉了,引起很多人的抱怨,觉得少了手势解锁的保护,个人信息容易泄漏了。。。

那么手势解锁功能是怎么是实现的呢,这里使用Quart2D来简单模拟一下,

先看下截图效果:

Quartz2D复习(二) ---  手势解锁-LMLPHP     Quartz2D复习(二) ---  手势解锁-LMLPHP    Quartz2D复习(二) ---  手势解锁-LMLPHP

按钮的有两个背景图片,一个默认样式,一个用于选中样式:

Quartz2D复习(二) ---  手势解锁-LMLPHP  Quartz2D复习(二) ---  手势解锁-LMLPHP

代码实现:

自定义view, 用来绘制所有路径,自定义view名称为:GestureLockView

GestureLockView.h文件:

#import <UIKit/UIKit.h>

@interface GestureLockView : UIView

@end

GestureLockView.m文件代码:

 //  手势解锁

 #import "GestureLockView.h"

 @interface GestureLockView()

 @property (nonatomic, retain) NSMutableArray *selectBtns;
@property (nonatomic, assign) CGPoint moveP; //移动的点 @end @implementation GestureLockView - (instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]){
[self addBtns];
NSLog(@"initWithFrame: %s", __func__);
}
return self;
} //解析xib的时候调用
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
if (self = [super initWithCoder:aDecoder]){
NSLog(@"initWithCoder: %s", __func__);
[self addBtns];
}
return self;
} //添加子按钮
- (void)addBtns{
for (int i = ; i < ; i++) {
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn setBackgroundImage:[UIImage imageNamed:@"gesture_node_normal"] forState:UIControlStateNormal];
[btn setBackgroundImage:[UIImage imageNamed:@"gesture_node_highlighted"] forState:UIControlStateSelected];
[btn setUserInteractionEnabled:NO]; //设置不能和用户进行交互
[btn setTag:i + ]; //设置标识
[self addSubview:btn];
}
} - (NSMutableArray *)selectBtns{
if (_selectBtns == nil){
_selectBtns = [[NSMutableArray alloc] init];
}
return _selectBtns;
} //触摸开始
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(@"触摸开始..."); self.moveP = [self getPoint:touches];
UIButton *btn = [self getBtn:self.moveP]; if (btn != nil){
[self.selectBtns addObject:btn];
btn.selected = YES;
}
} //触摸移动, 设置被选中的按钮
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
//NSLog(@"触摸移动");
self.moveP = [self getPoint:touches];
UIButton *btn = [self getBtn:self.moveP]; if (btn != nil && btn.selected == NO){
[self.selectBtns addObject:btn];
btn.selected = YES;
} [self setNeedsDisplay]; //从新绘制
} //触摸结束,一切归空
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
NSMutableString *str = [[NSMutableString alloc] init];
for (UIButton * btn in self.selectBtns) {
[str appendFormat:@"%i", btn.tag];
btn.selected = NO;
} self.moveP = CGPointZero;
[self setNeedsDisplay];
[self.selectBtns removeAllObjects]; // UILabel *lbl = [[UILabel alloc] init];
// lbl.text = [NSString stringWithFormat:@"密码是:%@", str];
// lbl.frame = CGRectMake(80, 150, 200, 30);
// [lbl setBackgroundColor:[UIColor whiteColor]];
// [lbl setTextAlignment:NSTextAlignmentCenter];
// [self addSubview:lbl];
//
// [UIView animateWithDuration:5.0 animations:^{
// lbl.alpha = 0.1;
// } completion:^(BOOL finished) {
// [lbl removeFromSuperview];
// }]; UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"设置结果为" message:str delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
[alert show];
} //监听触摸移动,获取触摸坐标
- (CGPoint)getPoint: (NSSet *)touches{
UITouch *touch = [touches anyObject]; //获取当前接触点
return [touch locationInView:self]; //获取当前触点在父对象中的位置
} //根据坐标获取按钮对象
- (UIButton *)getBtn: (CGPoint)point{
for (UIButton * btn in self.subviews) {
if (CGRectContainsPoint(btn.frame, point)){
return btn;
}
}
return nil;
} //布局子控件的坐标位置
- (void)layoutSubviews{
CGFloat width = ;
CGFloat height = width;
CGFloat cols = ;
CGFloat rows = cols;
CGFloat margin = ([UIScreen mainScreen].bounds.size.width - width * cols) / (cols + ); for (int i = ; i < rows; i++) {
for (int j = ; j < cols; j++) {
CGFloat x = j * (width + margin) + margin;
CGFloat y = i * (height + margin) + margin;
UIButton *btn = (UIButton *)[self.subviews objectAtIndex: (i * rows) + j];
btn.frame = CGRectMake(x, y, width, height);
}
}
} //
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
//从新绘制
- (void)drawRect:(CGRect)rect {
//1、获取当前上下文
CGContextRef ctr = UIGraphicsGetCurrentContext();
//2、绘制路径
UIBezierPath *path = [UIBezierPath bezierPath];
CGContextSetLineWidth(ctr, ); //设置线段宽度
CGContextSetLineJoin(ctr, kCGLineJoinRound); //设置转折点
[[UIColor whiteColor] set]; //设置路径颜色 [path moveToPoint:self.moveP]; for (int i = ; i < self.selectBtns.count; i++) {
UIButton *btn = (UIButton *)[self.selectBtns objectAtIndex:i];
CGPoint point = btn.center; if (i == ){
[path moveToPoint:point];
}
else{
[path addLineToPoint:point];
}
} if (!CGPointEqualToPoint(self.moveP, CGPointZero)){
[path addLineToPoint:self.moveP]; //重点路径
}
//3、把路径添加到上下文中
CGContextAddPath(ctr, path.CGPath); //4、渲染
CGContextStrokePath(ctr);
} @end

自定义控制器来展示自定义手势解锁view

GestureLockViewController.h :

#import <UIKit/UIKit.h>

@interface GestureLockViewController : UIViewController

@end

GestureLockViewController.m文件代码:

 #import "GestureLockViewController.h"
#import "GestureLockView.h" @interface GestureLockViewController () @end @implementation GestureLockViewController - (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.view setBackgroundColor:[UIColor whiteColor]]; //返回按钮
UIButton *preBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[preBtn setFrame:CGRectMake(, , , )];
[preBtn setBackgroundColor:[UIColor purpleColor]];
[preBtn setTitle:@"返回" forState:UIControlStateNormal];
[preBtn addTarget:self action:@selector(prePage) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:preBtn]; //增加view
CGSize size = [UIScreen mainScreen].bounds.size;
GestureLockView *view = [[GestureLockView alloc] initWithFrame:CGRectMake(, , size.width, size.width + )];
[view setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:view];
} - (void)prePage{
[self dismissViewControllerAnimated:YES completion:nil];
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} /*
#pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/ @end
05-11 10:52