首页 > 代码库 > 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和触摸事件的简单使用:手势解锁