01-手势解锁
2018-11-05 本文已影响10人
小胖子2号
1.jpeg
分析界面
- 当手指在上面移动时,当移动到一个按钮范围内当中, 它会把按钮给成为选中的状态.
2.并且把第一个选中的按钮当做一个线的起点,当手指移动到某个按钮上时,就会添加一根线到选中的那妞上.
3.当手指松开时,所有按钮取消选中.所有的线都清空.
实现思路:(自定义view,以后可以直接在项目中用)
先判断点前手指在不在当前的按钮上.如果在按钮上,就把当前按钮成为选中状态.
并且把当前选中的按钮添加到一个数组当中.如果当前按钮已经是选中状态,就不需要再添加到数组中了.
每次移动时,都让它进行重绘.
在绘图当中,遍历出所有的选中的按钮,
判断数组当中的第一个无素,如果是第一个,那么就把它设为路径的起点.其它都在添加一根线到按钮的圆心.
如果当前点不在按钮上.那么就记录住当前手指所在的点.直接从起点添加一根线到当前手指所在的点.
实现步骤:
1.搭建界面
界面是一个九宫格的布局.九宫格实现思路.
先确定有多少列 cloum = 3;
计算出每列之间的距离
计算为: CGFloat margin = (当前View的宽度 - 列数 * 按钮的宽度) / 总列数 + 1
每一列的X的值与它当前所在的行有关
当前所在的列为:curColum = i % cloum
每一行的Y的值与它当前所在的行有关.
当前所在的行为:curRow = i / cloum
每一个按钮的X值为, margin + 当前所在的列 * (按钮的宽度+ 每个按钮之间的间距)
每一个按钮的Y值为 当前所在的行 * (按钮的宽度 + 每个按钮之间的距离)
具体代码为:
总列数
int colum = 3;
每个按钮的宽高
CGFloat btnWH = 74;
每个按钮之间的距离
CGFloat margin = (self.bounds.size.width - colum * btnWH) / (colum + 1);
for(int i = 0; i < self.subviews.count; i++ ){
当前所在的列
int curColum = i % colum;
当前所在的行
int curRow = i / colum;
CGFloat x = margin + (btnWH + margin) * curColum;
CGFloat y = (btnWH + margin) * curRow;
取出所有的子控件
UIButton *btn = self.subviews[i];
btn.frame = CGRectMake(x, y, btnWH, btnWH);
}
2.监听手指在上面的点击,移动,松开都需要做操作.
2.1在手指开始点击屏幕时,如果当前手指所在的点在按钮上, 那就让按钮成为选中状态.
所以要遍历出所有的按钮,判断当前手指所在的点在不在按钮上,
如何判断当前点在不在按钮上?
当前方法就是判断一个点在不在某一个区域,如果在的话会返回Yes,不在的话,返回NO.
CGRectContainsPoint(btn.frame, point)
在手指点击屏幕的时候,要做的事分别有
1.获取当前手指所在的点.
UITouch *touch = [touches anyObject];
CGPoint curP = [touch locationInView:self];
2.判断当前点在不在按钮上.
for (UIButton *btn in self.subviews) {
if (CGRectContainsPoint(btn.frame, point)) {
return btn;
}
}
3.如果当前点在按钮上,并且当前按钮不是选中的状态.
那么把当前的按钮成为选中状态.
并且把当前的按钮添加到数组当中.
2.2 当手指在移动的时也需要判断.
判断当前点在按钮上,并且当前按钮不是选中的状态.
那么把当前的按钮成为选中状态.
并且把当前的按钮添加到数组当中.
在移动的时候做重绘的工作.
2.3 当手指离开屏幕时.
取出所有的选中按钮,把所有选中按钮取消选中状态.
清空选中按钮的数组.
绘重绘的工作.
3. 在绘图方法当中.
创建路径
遍历出有的选中按钮.如果是第一个按钮,把第一个按钮的中心点当做是路径的起点.
其它按钮都直接添加一条线,到该按钮的中心.
遍历完所有的选中按钮后.
最后添加一条线到当前手指所在的点.
具体代码如下:
#import "ClockView.h"
@interface ClockView()
/**
* 选中的按钮数组.
*/
@property(nonatomic,strong)NSMutableArray *selectBtn;
/**
* 当前手指移动的点
*/
@property(nonatomic,assign)CGPoint curP;
@end
@implementation ClockView
//懒加载数组.
-(NSMutableArray *)selectBtn{
if (_selectBtn == nil) {
_selectBtn = [NSMutableArray array];
}
return _selectBtn;
}
-(void)awakeFromNib{
//初始化
[self setUP];
}
-(instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
//初始化
[self setUP];
}
return self;
}
//初始化
- (void)setUP{
for (int i = 0; i < 9; i++) {
//添加按钮
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
//添加按钮时设置一个Tag以便记录每一个选中的按钮
btn.tag = i;
//让按钮不能够接受事件,原因是当前按钮会拦截事件.
btn.userInteractionEnabled = NO;
//设置图片
[btn setImage:[UIImage imageNamed:@"gesture_node_normal"] forState:UIControlStateNormal];
//设置选中状态的下图片
[btn setImage:[UIImage imageNamed:@"gesture_node_highlighted"] forState:UIControlStateSelected];
[self addSubview:btn];
}
}
/**
* 获取当前手指所在的点
*
* @param touches touches集合
*
* @return 当前手指所在的点.
*/
- (CGPoint)getCurrentPoint:(NSSet *)touches{
UITouch *touch = [touches anyObject];
return [touch locationInView:self];
}
/**
* 判断一个点在不在按钮上.
*
* @param point 当前点
*
* @return 如果在按钮上, 返回当前按钮, 如果不在返回nil.
*/
- (UIButton *)btnRectContainsPoint:(CGPoint)point{
for (UIButton *btn in self.subviews) {
if (CGRectContainsPoint(btn.frame, point)) {
//在按钮上.返回当前按钮
return btn;
}
}
return nil;
}
//手指点击时让按钮成选中状态
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//判断当前手指在不在按钮上,如果在按钮上, 让按钮成为选中状态.
//1.获取当前手指所在的点
CGPoint curP = [self getCurrentPoint:touches];
//2.判断当前手指所在的点在不在按钮上.
UIButton *btn = [self btnRectContainsPoint:curP];
if (btn && btn.selected == NO) {//如果按钮已经是选中状态,就不让它再添加到数组当中
//让按钮成为选中状态
btn.selected = YES;
//把选中按钮添加到数组当中
[self.selectBtn addObject:btn];
}
}
//手指移动时,按钮选中,连线到当前选中的按钮
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
//判断当前手指在不在按钮上,如果在按钮上, 让按钮成为选中状态.
//1.获取当前手指所在的点
CGPoint curP = [self getCurrentPoint:touches];
//2.判断当前手指所在的点在不在按钮上.
UIButton *btn = [self btnRectContainsPoint:curP];
if (btn && btn.selected == NO) {//如果按钮已经是选中状态,就不让它再添加到数组当中
//让按钮成为选中状态
btn.selected = YES;
//把选中按钮添加到数组当中
[self.selectBtn addObject:btn];
}
//每次做一次重绘.
[self setNeedsDisplay];
//记录当前手指移动的点.
self.curP = curP;
}
//手指松开时,按钮取消选中状态,清空所有的连线.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
if (self.selectBtn.count) {
//1.取消所有选中的按钮,查看选中按钮的顺序
NSMutableString *str = [NSMutableString string];
for (UIButton *btn in self.selectBtn) {
[str appendFormat:@"%ld",btn.tag];
btn.selected = NO;
}
//2.清空所有的连线.
[self.selectBtn removeAllObjects];
//3.重绘
[self setNeedsDisplay];
//查看是否是第一次设置密码
NSString *keyPwd = [[NSUserDefaults standardUserDefaults] objectForKey:@"keyPwd"];
if (!keyPwd) {
[[NSUserDefaults standardUserDefaults] setObject:str forKey:@"keyPwd"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(@"第一次输入密码");
} else {
if ([keyPwd isEqualToString:str]) {
NSLog(@"密码正确");
UIAlertView *alertV = [[UIAlertView alloc] initWithTitle:@"手势输入正确" message:nil delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
[alertV show];
} else {
NSLog(@"密码错误");
UIAlertView *alertV = [[UIAlertView alloc] initWithTitle:@"手势输入错误" message:nil delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
[alertV show];
}
}
NSLog(@"选中按钮顺序为:%@",str);
}
}
//布局子控件
- (void)layoutSubviews{
[super layoutSubviews];
//总列数
int cloumn = 3;
CGFloat btnWH = 74;
//每列之间的间距
CGFloat margin = (self.bounds.size.width - cloumn * btnWH) / (cloumn + 1);
//当前所在的列
int curClounm = 0;
//当前所在的行
int curRow = 0;
CGFloat x = 0;
CGFloat y = 0;
//取出所有的控件
for (int i = 0; i < self.subviews.count; i++) {
curClounm = i % cloumn;
curRow = i / cloumn;
x = margin + (margin + btnWH) * curClounm;
y = (margin +btnWH) * curRow;
UIButton *btn = self.subviews[i];
//设置按钮的尺寸位置
btn.frame = CGRectMake(x, y, btnWH, btnWH);
}
}
- (void)drawRect:(CGRect)rect {
//如果数组当中没有元素,就不让它进行绘图.直接返回.
if(self.selectBtn.count <= 0) return;
//创建路径.
UIBezierPath *path = [UIBezierPath bezierPath];
//取出所有保存的选中按钮连线.
for(int i = 0; i < self.selectBtn.count;i++){
UIButton *btn = self.selectBtn[i];
//判断当前按钮是不是第一个,如果是第一个,把它的中心设置为路径的起点.
if(i == 0){
//设置起点.
[path moveToPoint:btn.center];
}else{
//添加一根线到当前按钮的圆心.
[path addLineToPoint:btn.center];
}
}
//连完先中的按钮后, 在选中按钮之后,添加一根线到当前手指所在的点.
[path addLineToPoint:self.curP];
//设置颜色
[[UIColor redColor] set];
//设置线宽
[path setLineWidth:10];
//设置线的连接样式
[path setLineJoinStyle:kCGLineJoinRound];
//绘制路径.
[path stroke];
}
@end