iOS开发UI篇—实现一个简单的手势解锁应用(完善)
一、需要实现的效果
二、应用完善
1.绘制不处于按钮范围内的连线
2.解决bug(完善)
bug1:如果在began方法中通知view绘图,那么会产生bug。因为,当前点没有清空,在手指移开之后要清空当前点。可以在绘制前进行判断,如果当前点是(0,0)那么就不划线。或者在began方法中不进行重绘。
bug2:无限菊花。自定义view的背景色为默认的(黑色),只要重写了drawrect方法,view默认的背景颜色就是黑色的,因为上下文默认的颜色是黑色的。会有缓存,出现无限菊花。可以通过在每次绘制前对上下文进行清空。
调整后的效果:
注意点:当自定义view的背景颜色为默认的时候,会有缓存。
bug3:没有当前点(没有起点)。判断数组中是否有按钮,如果有按钮,那么就有起点不会报错。
三、获取用户输入的手势密码
实现效果:
获取用户的手势(密码)
思路:当用户手指离开屏幕的时候,获取用户输入的密码(手势)。需要每个按钮表示一个唯一的数字,可以考虑使用tag值,作为按钮的唯一标识。创建一个可变的字符串,通过一个循环,把数组中的每个按钮的tag值添加到可变字符串中。
提示:考虑把获取用户输入密码环节进行封装。比较用户密码是否正确应该在控制器的业务逻辑中进行处理。
思路:自定义一个协议,设置代理,获取用户输入的密码后,告诉代理用户输入的密码。
设置代理
代码:
在自定义view的头文件YYLockView.h中自定义一个协议。
1 // 2 // YYLockView.h 3 // 01-手势解锁(基本) 4 // 5 // Created by apple on 14-6-18. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import <UIKit/UIKit.h> 10 11 @class YYLockView; 12 @protocol YYLockViewDelegate <NSObject> 13 //自定义一个协议 14 //协议方法,把当前视图作为参数 15 -(void)LockViewDidClick:(YYLockView *)lockView andPwd:(NSString *)pwd; 16 @end 17 18 @interface YYLockView : UIView 19 //代理 20 @property(nonatomic,weak) IBOutlet id<YYLockViewDelegate>delegate; 21 @end
在Touchesended方法中通知代理
1 //取出用户输入的密码 2 //创建一个可变的字符串,用来保存用户密码 3 NSMutableString *result=[NSMutableString string]; 4 for (UIButton *btn in self.buttons) { 5 [result appendFormat:@"%d",btn.tag]; 6 } 7 NSLog(@"用户输入的密码为:%@",result); 8 //通知代理,告知用户输入的密码 9 if ([self.delegate respondsToSelector:@selector(LockViewDidClick:andPwd:)]) { 10 [self.delegate LockViewDidClick:self andPwd:result]; 11 }
在主控制器中实现协议中的方法
1 #import "YYViewController.h" 2 #import "YYLockView.h" 3 4 @interface YYViewController ()<YYLockViewDelegate> 5 6 @end 7 8 @implementation YYViewController 9 10 - (void)viewDidLoad 11 { 12 [super viewDidLoad]; 13 } 14 15 -(void)LockViewDidClick:(YYLockView *)lockView andPwd:(NSString *)pwd 16 { 17 NSLog(@"密码=%@",pwd); 18 } 19 @end
四、附录
完整代码:
自定义的view中,YYLockView.m文件
1 // 2 // YYLockView.m 3 // 01-手势解锁(基本) 4 // 5 // Created by apple on 14-6-18. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYLockView.h" 10 11 @interface YYLockView () 12 @property(nonatomic,strong)NSMutableArray *buttons; 13 //定义一个属性,记录当前点 14 @property(nonatomic,assign)CGPoint currentPoint; 15 @end 16 @implementation YYLockView 17 18 #pragma mark-懒加载 19 -(NSMutableArray *)buttons 20 { 21 if (_buttons==nil) { 22 _buttons=[NSMutableArray array]; 23 } 24 return _buttons; 25 } 26 27 //界面搭建 28 - (id)initWithFrame:(CGRect)frame 29 { 30 self = [super initWithFrame:frame]; 31 if (self) { 32 [self setup]; 33 } 34 return self; 35 } 36 37 -(id)initWithCoder:(NSCoder *)aDecoder 38 { 39 if (self=[super initWithCoder:aDecoder]) { 40 [self setup]; 41 } 42 return self; 43 } 44 //在界面上创建9个按钮 45 -(void)setup 46 { 47 //1.创建9个按钮 48 for (int i=0; i<9; i++) { 49 UIButton *btn=[UIButton buttonWithType:UIButtonTypeCustom]; 50 //2.设置按钮的状态背景 51 [btn setBackgroundImage:[UIImage imageNamed:@"gesture_node_normal"] forState:UIControlStateNormal]; 52 [btn setBackgroundImage:[UIImage imageNamed:@"gesture_node_highlighted"] forState:UIControlStateSelected]; 53 //3.把按钮添加到视图中 54 [self addSubview:btn]; 55 //4.禁止按钮的点击事件 56 btn.userInteractionEnabled=NO; 57 //5.设置每个按钮的tag 58 btn.tag=i; 59 } 60 } 61 62 //4.设置按钮的frame 63 -(void)layoutSubviews 64 { 65 //4.1需要先调用父类的方法 66 [super layoutSubviews]; 67 for (int i=0; i<self.subviews.count; i++) { 68 //4.2取出按钮 69 UIButton *btn=self.subviews[i]; 70 71 //4.3九宫格法计算每个按钮的frame 72 CGFloat row = i/3; 73 CGFloat loc = i%3; 74 CGFloat btnW=74; 75 CGFloat btnH=74; 76 CGFloat padding=(self.frame.size.width-3*btnW)/4; 77 CGFloat btnX=padding+(btnW+padding)*loc; 78 CGFloat btnY=padding+(btnW+padding)*row; 79 btn.frame=CGRectMake(btnX, btnY, btnW, btnH); 80 } 81 } 82 83 //5.监听手指的移动 84 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 85 { 86 CGPoint starPoint=[self getCurrentPoint:touches]; 87 UIButton *btn=[self getCurrentBtnWithPoint:starPoint]; 88 89 if (btn && btn.selected != YES) { 90 btn.selected=YES; 91 [self.buttons addObject:btn]; 92 } 93 // [self setNeedsDisplay]; 94 } 95 96 -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 97 { 98 CGPoint movePoint=[self getCurrentPoint:touches]; 99 UIButton *btn=[self getCurrentBtnWithPoint:movePoint]; 100 //存储按钮 101 //已经连过的按钮,不可再连 102 if (btn && btn.selected != YES) { 103 //设置按钮的选中状态 104 btn.selected=YES; 105 //把按钮添加到数组中 106 [self.buttons addObject:btn]; 107 } 108 //记录当前点(不在按钮的范围内) 109 self.currentPoint=movePoint; 110 //通知view重新绘制 111 [self setNeedsDisplay]; 112 } 113 114 //手指离开的时候清除线条 115 -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 116 { 117 //取出用户输入的密码 118 //创建一个可变的字符串,用来保存用户密码 119 NSMutableString *result=[NSMutableString string]; 120 for (UIButton *btn in self.buttons) { 121 [result appendFormat:@"%d",btn.tag]; 122 } 123 NSLog(@"用户输入的密码为:%@",result); 124 //通知代理,告知用户输入的密码 125 if ([self.delegate respondsToSelector:@selector(LockViewDidClick:andPwd:)]) { 126 [self.delegate LockViewDidClick:self andPwd:result]; 127 } 128 129 //重置按钮的状态 130 // for (UIButton *btn in self.buttons) { 131 // btn.selected=NO; 132 //// [btn setSelected:NO]; 133 // } 134 135 //调用该方法,它就会让数组中的每一个元素都调用setSelected:方法,并给每一个元素传递一个NO参数 136 [self.buttons makeObjectsPerformSelector:@selector(setSelected:) withObject:@(NO)]; 137 //清空数组 138 [self.buttons removeAllObjects]; 139 [self setNeedsDisplay]; 140 141 //清空当前点 142 self.currentPoint=CGPointZero; 143 } 144 145 //对功能点进行封装 146 -(CGPoint)getCurrentPoint:(NSSet *)touches 147 { 148 UITouch *touch=[touches anyObject]; 149 CGPoint point=[touch locationInView:touch.view]; 150 return point; 151 } 152 -(UIButton *)getCurrentBtnWithPoint:(CGPoint)point 153 { 154 for (UIButton *btn in self.subviews) { 155 if (CGRectContainsPoint(btn.frame, point)) { 156 return btn; 157 } 158 } 159 return Nil; 160 } 161 162 //重写drawrect:方法 163 -(void)drawRect:(CGRect)rect 164 { 165 //获取上下文 166 CGContextRef ctx=UIGraphicsGetCurrentContext(); 167 //在每次绘制前,清空上下文 168 CGContextClearRect(ctx, rect); 169 170 //绘图(线段) 171 for (int i=0; i<self.buttons.count; i++) { 172 UIButton *btn=self.buttons[i]; 173 if (0==i) { 174 //设置起点(注意连接的是中点) 175 // CGContextMoveToPoint(ctx, btn.frame.origin.x, btn.frame.origin.y); 176 CGContextMoveToPoint(ctx, btn.center.x, btn.center.y); 177 }else 178 { 179 // CGContextAddLineToPoint(ctx, btn.frame.origin.x, btn.frame.origin.y); 180 CGContextAddLineToPoint(ctx, btn.center.x, btn.center.y); 181 } 182 } 183 184 //当所有按钮的中点都连接好之后,再连接手指当前的位置 185 //判断数组中是否有按钮,只有有按钮的时候才绘制 186 if (self.buttons.count !=0) { 187 CGContextAddLineToPoint(ctx, self.currentPoint.x, self.currentPoint.y); 188 } 189 190 //渲染 191 //设置线条的属性 192 CGContextSetLineWidth(ctx, 10); 193 CGContextSetLineJoin(ctx, kCGLineJoinRound); 194 CGContextSetLineCap(ctx, kCGLineCapRound); 195 CGContextSetRGBStrokeColor(ctx, 20/255.0, 107/255.0, 153/255.0, 1); 196 CGContextStrokePath(ctx); 197 } 198 @end
YYLockView.h文件代码
1 // 2 // YYLockView.h 3 // 01-手势解锁(基本) 4 // 5 // Created by apple on 14-6-18. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import <UIKit/UIKit.h> 10 11 @class YYLockView; 12 @protocol YYLockViewDelegate <NSObject> 13 //自定义一个协议 14 //协议方法,把当前视图作为参数 15 -(void)LockViewDidClick:(YYLockView *)lockView andPwd:(NSString *)pwd; 16 @end 17 18 @interface YYLockView : UIView 19 //代理 20 @property(nonatomic,weak) IBOutlet id<YYLockViewDelegate>delegate; 21 @end
主控制器文件
1 // 2 // YYViewController.m 3 // 01-手势解锁(基本) 4 // 5 // Created by apple on 14-6-18. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYViewController.h" 10 #import "YYLockView.h" 11 12 @interface YYViewController ()<YYLockViewDelegate> 13 14 @end 15 16 @implementation YYViewController 17 18 - (void)viewDidLoad 19 { 20 [super viewDidLoad]; 21 } 22 23 -(void)LockViewDidClick:(YYLockView *)lockView andPwd:(NSString *)pwd 24 { 25 NSLog(@"密码=%@",pwd); 26 } 27 @end
iOS开发UI篇—实现一个简单的手势解锁应用(完善)
时间: 2024-10-23 12:10:17