首页 > 代码库 > UI进阶--Quartz2D和触摸事件的简单使用:手势解锁

UI进阶--Quartz2D和触摸事件的简单使用:手势解锁

需求:实现一个简易的手势解锁应用,具体效果如下图所示:

技术分享

实现步骤:

1、代码创建界面,自定义一个view,设置view的背景,颜色等属性;

2在自定义的view中,定义2个属性,一个是存储被选中按钮的可变数组,另外一个是最后的触摸点(CGPoint);

3、重写initWithFrame方法,在这里,自定义一个方法给initWithFrame方法调用即可,这个自定义的方法里,初始化9个按钮,设置每个按钮的tag,正常状态下的图片以及选中状态的图片,并设置和用户的交互为NO

4在自定义的view中的layoutSubviews方法中,自定义9个按钮;

5、在touchesBegan:touchesMoved:方法中,判断触摸点是否在view上的9个按钮中,如果在,那么设置按钮的选中状态;(在这里,只写其中一个方法即可,另外一个方法直接调用)

5.1、进行遍历,并把选中的按钮放在选中按钮的可变数组中,并记录最后的触摸点;

5.2、在最后记得重绘图形,调用setNeedsDisplay方法;

6、在drawRect:方法中,绘制选中按钮之间的连线;

6.1、遍历选中按钮数组,得到选中按钮的数量,如果为0,直接返回;

6.2、使用UIBezierPath画线;

6.3、对绘制的线进行线宽,颜色、样式等设置

6.4、对绘制的线进行渲染;

7、在touchesEnded:方法中取消连线,并移除选中的按钮,最后重绘图形;

8、选择完密码后,把密码传回给控制器,让控制器判断选择是否正确;

8.1、在自定义的view中设置代理;

8.2、在touchesEnded:方法中拼接选中按钮的索引;

8.3、通知代理按钮的选择;

具体实现代码:

 

Controller:

 1 // 2 //  ViewController.m 3 //  1-4-Deblocking 4 // 5 //  Created by xiaomoge on 15/1/4. 6 //  Copyright (c) 2015年 xiaomoge. All rights reserved. 7 // 8  9 #import "ViewController.h"10 #import "DeblockingView.h"11 @interface ViewController () <DeblockingViewDelegate>12 13 @end14 15 @implementation ViewController16 17 - (void)viewDidLoad {18     [super viewDidLoad];19     //设置背景颜色20     self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"Home_refresh_bg"]];21     //取得当前屏幕的宽度22     CGFloat screenW = [UIScreen mainScreen].bounds.size.width;23     //初始化一个DeblockingView24     DeblockingView *deblockingView = [[DeblockingView alloc] initWithFrame:CGRectMake(0, 0, screenW, screenW)];25     //设置背景颜色26     deblockingView.backgroundColor = [UIColor clearColor];27    //居中显示28     deblockingView.center = self.view.center;29    //设置代理30     deblockingView.delegate = self;31     [self.view addSubview:deblockingView];32 }33 #pragma mark - DeblockingViewDelegate方法34 - (void)selectBtn:(DeblockingView *)deblockingView andSelectPwd:(NSString *)pwd {35     NSString *tips;36     if ([pwd isEqualToString:@"03478"]) {//设置一个固定的密码37         tips = @"解锁成功";38     }else {39         tips = @"密码错误";40     }41     //弹出窗口提示42     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:tips delegate:nil cancelButtonTitle:nil otherButtonTitles:@"确定", nil];43     [alert show];44 }45 @end

 

View:

 1 // 2 //  DeblockingView.h 3 //  1-4-Deblocking 4 // 5 //  Created by xiaomoge on 15/1/4. 6 //  Copyright (c) 2015年 xiaomoge. All rights reserved. 7 // 8  9 #import <UIKit/UIKit.h>10 @class DeblockingView;11 @protocol DeblockingViewDelegate <NSObject>12 @optional13 - (void)selectBtn:(DeblockingView *)deblockingView andSelectPwd:(NSString *)pwd;14 15 @end16 @interface DeblockingView : UIView17 @property (nonatomic,assign) id<DeblockingViewDelegate> delegate;18 @end

 

  1 //  2 //  DeblockingView.m  3 //  1-4-Deblocking  4 //  5 //  Created by xiaomoge on 15/1/4.  6 //  Copyright (c) 2015年 xiaomoge. All rights reserved.  7 //  8   9 #import "DeblockingView.h" 10 @interface DeblockingView () 11 /* 12  选中的按钮数组 13  */ 14 @property (nonatomic,strong) NSMutableArray *selectedBtns; 15 /* 16  最后触摸到的点 17  */ 18 @property (nonatomic,assign) CGPoint lastPoint; 19 @end 20 @implementation DeblockingView 21 //懒加载 22 - (NSMutableArray *)selectedBtns { 23     if (!_selectedBtns) { 24         _selectedBtns = [NSMutableArray array]; 25     } 26     return _selectedBtns; 27 } 28 //绘制选中按钮间的连线 29 - (void)drawRect:(CGRect)rect { 30     //取得当前选中的按钮的个数 31     NSInteger selectBtnCount = self.selectedBtns.count; 32     //如果被选中的按钮个数为0,即返回。 33     if (selectBtnCount == 0) return; 34      35     UIBezierPath *path = [UIBezierPath bezierPath]; 36     for (NSInteger i = 0; i < selectBtnCount; i++) { 37         //取得按钮先连接的点 38         CGPoint btnCenter = [self.selectedBtns[i] center]; 39         if (i == 0) {//设置为起点 40             [path moveToPoint:btnCenter]; 41         }else {//设置为连接点 42             [path addLineToPoint:btnCenter]; 43         } 44     } 45     //如果最后有未选中按钮的连线点 46     [path addLineToPoint:self.lastPoint]; 47     //设置连线的宽度 48     path.lineWidth = 8; 49     //设置连线的头尾样式 50     path.lineCapStyle = kCGLineCapRound; 51     //设置连线的连接点样式 52     path.lineJoinStyle = kCGLineJoinRound; 53     //设置连线的颜色 54     [[UIColor greenColor] set]; 55     //渲染 56     [path stroke]; 57 } 58 //加载完view后会调用这个方法 59 - (void)layoutSubviews { 60     [super layoutSubviews];//别忘记要写父类的方法 61     //取得按钮的数量 62     NSInteger btnCount = self.subviews.count; 63     //设置按钮的宽度 64     CGFloat btnW = 74; 65     //设置按钮的高度 66     CGFloat btnH = 74; 67     //设置按钮间的间距 68     CGFloat margin = (self.bounds.size.width - 3 * btnW) / 4; 69     for (int i = 0; i < btnCount; i++) { 70         //取得一个按钮 71         UIButton *btn = self.subviews[i]; 72         //获得当前的行号 73         int row = i / 3; 74         //获得当前列号 75         int culomns = i % 3; 76         //设置按钮的X(可参考应用管理中的计算) 77         CGFloat btnX = margin + culomns * (margin + btnW); 78         //设置按钮的Y 79         CGFloat btnY = margin + row * (margin + btnH); 80         btn.frame = CGRectMake(btnX, btnY, btnW, btnH); 81     } 82 } 83 //初始化方法 84 - (instancetype)initWithFrame:(CGRect)frame { 85     if (self = [super initWithFrame:frame]) { 86         [self setBtns]; 87     } 88     return self; 89 } 90 //设置9个按钮 91 - (void)setBtns { 92     for (int i = 0; i < 9; i++) { 93         UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; 94         btn.tag = i; 95         //设置按钮正常状态下的图片 96         [btn setImage:[UIImage imageNamed:@"gesture_node_normal"] forState:UIControlStateNormal]; 97         //设置按钮被选中时的图片 98         [btn setImage:[UIImage imageNamed:@"gesture_node_highlighted"] forState:UIControlStateSelected]; 99         //取消与用户的交互100         btn.userInteractionEnabled = NO;101         [self addSubview:btn];102     }103 }104 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {105     [self touchesMoved:touches withEvent:event];106 }107 108 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {109     //获取当前触摸点110     UITouch *touch = [touches anyObject];111     CGPoint touchPoint = [touch locationInView:touch.view];112     113     for (UIButton *btn in self.subviews) {114         if (CGRectContainsPoint(btn.frame, touchPoint)) {//判断触摸点是否在按钮的范围内115             if (btn.selected == NO) {//在按钮范围内,并且为未选中状态时116                 [self.selectedBtns addObject:btn];//加进选中按钮的数组117             }118             btn.selected = YES;119         }else {//否则设置这个点为最后的触摸点120             self.lastPoint = touchPoint;121         }122     }123     //重绘124     [self setNeedsDisplay];125 }126 127 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {128     //拼接选中按钮的tag作为密码129     NSMutableString *pwd = [NSMutableString string];130     for (UIButton *btn in self.selectedBtns) {131         [pwd appendFormat:@"%ld",btn.tag];132     }133     //如果代理实现了方法,通知代理对象134     if ([self.delegate respondsToSelector:@selector(selectBtn:andSelectPwd:)]) {135         [self.delegate selectBtn:self andSelectPwd:pwd];136     }137     //设置所有被选中的按钮为未选中状态138     [self.selectedBtns makeObjectsPerformSelector:@selector(setSelected:) withObject:@NO];139     //移除所有被选中的按钮140     [self.selectedBtns removeAllObjects];141     //重绘142     [self setNeedsDisplay];143 }144 @end

最后的效果图:

技术分享技术分享

UI进阶--Quartz2D和触摸事件的简单使用:手势解锁