美文网首页
01-手势解锁

01-手势解锁

作者: 小胖子2号 | 来源:发表于2018-11-05 16:35 被阅读10次
    1.jpeg

    分析界面

    1. 当手指在上面移动时,当移动到一个按钮范围内当中, 它会把按钮给成为选中的状态.

    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
    

    相关文章

      网友评论

          本文标题:01-手势解锁

          本文链接:https://www.haomeiwen.com/subject/etpsxqtx.html