01-手勢解鎖

1.jpeg

分析界面

  1. 當(dāng)手指在上面移動時,當(dāng)移動到一個按鈕范圍內(nèi)當(dāng)中, 它會把按鈕給成為選中的狀態(tài).

2.并且把第一個選中的按鈕當(dāng)做一個線的起點,當(dāng)手指移動到某個按鈕上時,就會添加一根線到選中的那妞上.

3.當(dāng)手指松開時,所有按鈕取消選中.所有的線都清空.

實現(xiàn)思路:(自定義view,以后可以直接在項目中用)
    先判斷點前手指在不在當(dāng)前的按鈕上.如果在按鈕上,就把當(dāng)前按鈕成為選中狀態(tài).
    并且把當(dāng)前選中的按鈕添加到一個數(shù)組當(dāng)中.如果當(dāng)前按鈕已經(jīng)是選中狀態(tài),就不需要再添加到數(shù)組中了.
    每次移動時,都讓它進行重繪.
    在繪圖當(dāng)中,遍歷出所有的選中的按鈕,
    判斷數(shù)組當(dāng)中的第一個無素,如果是第一個,那么就把它設(shè)為路徑的起點.其它都在添加一根線到按鈕的圓心.
    如果當(dāng)前點不在按鈕上.那么就記錄住當(dāng)前手指所在的點.直接從起點添加一根線到當(dāng)前手指所在的點.

實現(xiàn)步驟:
1.搭建界面
    界面是一個九宮格的布局.九宮格實現(xiàn)思路.
    先確定有多少列  cloum = 3;
    計算出每列之間的距離
    計算為: CGFloat margin = (當(dāng)前View的寬度 - 列數(shù) * 按鈕的寬度) / 總列數(shù) + 1
    每一列的X的值與它當(dāng)前所在的行有關(guān)
    當(dāng)前所在的列為:curColum = i % cloum
    每一行的Y的值與它當(dāng)前所在的行有關(guān).
    當(dāng)前所在的行為:curRow = i / cloum
    
    每一個按鈕的X值為, margin + 當(dāng)前所在的列 * (按鈕的寬度+ 每個按鈕之間的間距)
    每一個按鈕的Y值為 當(dāng)前所在的行 * (按鈕的寬度 + 每個按鈕之間的距離)
    
    具體代碼為:
    總列數(shù)
    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++ ){
        當(dāng)前所在的列
        int curColum = i % colum;
        當(dāng)前所在的行
        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.監(jiān)聽手指在上面的點擊,移動,松開都需要做操作.
    
    2.1在手指開始點擊屏幕時,如果當(dāng)前手指所在的點在按鈕上, 那就讓按鈕成為選中狀態(tài).
        所以要遍歷出所有的按鈕,判斷當(dāng)前手指所在的點在不在按鈕上,
        如何判斷當(dāng)前點在不在按鈕上?
        當(dāng)前方法就是判斷一個點在不在某一個區(qū)域,如果在的話會返回Yes,不在的話,返回NO.
        CGRectContainsPoint(btn.frame, point)
    
        在手指點擊屏幕的時候,要做的事分別有
        1.獲取當(dāng)前手指所在的點.
            UITouch *touch = [touches anyObject];
            CGPoint curP =  [touch locationInView:self];
        2.判斷當(dāng)前點在不在按鈕上.
             for (UIButton *btn in self.subviews) {
                if (CGRectContainsPoint(btn.frame, point)) {
                      return btn;
                }
             }
        3.如果當(dāng)前點在按鈕上,并且當(dāng)前按鈕不是選中的狀態(tài).
          那么把當(dāng)前的按鈕成為選中狀態(tài).
          并且把當(dāng)前的按鈕添加到數(shù)組當(dāng)中.

    
    2.2 當(dāng)手指在移動的時也需要判斷.
          判斷當(dāng)前點在按鈕上,并且當(dāng)前按鈕不是選中的狀態(tài).
          那么把當(dāng)前的按鈕成為選中狀態(tài).
          并且把當(dāng)前的按鈕添加到數(shù)組當(dāng)中.
         在移動的時候做重繪的工作.
         
    2.3 當(dāng)手指離開屏幕時.
        取出所有的選中按鈕,把所有選中按鈕取消選中狀態(tài).
        清空選中按鈕的數(shù)組.
        繪重繪的工作.
        
        
 3. 在繪圖方法當(dāng)中.
    創(chuàng)建路徑 
    遍歷出有的選中按鈕.如果是第一個按鈕,把第一個按鈕的中心點當(dāng)做是路徑的起點.
    其它按鈕都直接添加一條線,到該按鈕的中心.
    
    遍歷完所有的選中按鈕后.
    最后添加一條線到當(dāng)前手指所在的點.

具體代碼如下:

#import "ClockView.h"

@interface ClockView()

/**
 *  選中的按鈕數(shù)組.
 */
@property(nonatomic,strong)NSMutableArray *selectBtn;

/**
 *  當(dāng)前手指移動的點
 */
@property(nonatomic,assign)CGPoint curP;
@end


@implementation ClockView

//懶加載數(shù)組.
-(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];
        
        //添加按鈕時設(shè)置一個Tag以便記錄每一個選中的按鈕
        btn.tag = i;
        
        //讓按鈕不能夠接受事件,原因是當(dāng)前按鈕會攔截事件.
        btn.userInteractionEnabled = NO;
        
        //設(shè)置圖片
        [btn setImage:[UIImage imageNamed:@"gesture_node_normal"] forState:UIControlStateNormal];
        
        //設(shè)置選中狀態(tài)的下圖片
        [btn setImage:[UIImage imageNamed:@"gesture_node_highlighted"] forState:UIControlStateSelected];
        [self addSubview:btn];
    }  
}

/**
 *  獲取當(dāng)前手指所在的點
 *
 *  @param touches touches集合
 *
 *  @return 當(dāng)前手指所在的點.
 */
- (CGPoint)getCurrentPoint:(NSSet *)touches{
    
    UITouch *touch = [touches anyObject];
    return [touch locationInView:self];
}

/**
 *  判斷一個點在不在按鈕上.
 *
 *  @param point 當(dāng)前點
 *
 *  @return 如果在按鈕上, 返回當(dāng)前按鈕, 如果不在返回nil.
 */
- (UIButton *)btnRectContainsPoint:(CGPoint)point{

    for (UIButton *btn in self.subviews) {
        
        if (CGRectContainsPoint(btn.frame, point)) {
            //在按鈕上.返回當(dāng)前按鈕
            return btn;
        }
    }
    return nil;
}


//手指點擊時讓按鈕成選中狀態(tài)
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

    //判斷當(dāng)前手指在不在按鈕上,如果在按鈕上, 讓按鈕成為選中狀態(tài).
    //1.獲取當(dāng)前手指所在的點
    CGPoint curP = [self getCurrentPoint:touches];
    
    //2.判斷當(dāng)前手指所在的點在不在按鈕上.
   UIButton *btn  = [self btnRectContainsPoint:curP];
    
    if (btn && btn.selected == NO) {//如果按鈕已經(jīng)是選中狀態(tài),就不讓它再添加到數(shù)組當(dāng)中
        //讓按鈕成為選中狀態(tài)
        btn.selected = YES;
        //把選中按鈕添加到數(shù)組當(dāng)中
        [self.selectBtn addObject:btn];      
    }    
}

//手指移動時,按鈕選中,連線到當(dāng)前選中的按鈕
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
    //判斷當(dāng)前手指在不在按鈕上,如果在按鈕上, 讓按鈕成為選中狀態(tài).
    //1.獲取當(dāng)前手指所在的點
    CGPoint curP = [self getCurrentPoint:touches];
    //2.判斷當(dāng)前手指所在的點在不在按鈕上.
    UIButton *btn  = [self btnRectContainsPoint:curP];
    if (btn && btn.selected == NO) {//如果按鈕已經(jīng)是選中狀態(tài),就不讓它再添加到數(shù)組當(dāng)中
        //讓按鈕成為選中狀態(tài)
        btn.selected = YES;
        //把選中按鈕添加到數(shù)組當(dāng)中
        [self.selectBtn addObject:btn];
    }
    //每次做一次重繪.
    [self setNeedsDisplay];
    //記錄當(dāng)前手指移動的點.
    self.curP = curP;
}

//手指松開時,按鈕取消選中狀態(tài),清空所有的連線.
-(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];
        
        //查看是否是第一次設(shè)置密碼
        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];
    //總列數(shù)
    int cloumn = 3;
    CGFloat btnWH = 74;
    //每列之間的間距
    CGFloat margin = (self.bounds.size.width - cloumn * btnWH) / (cloumn + 1);
    
    //當(dāng)前所在的列
    int curClounm = 0;
    //當(dāng)前所在的行
    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];
        //設(shè)置按鈕的尺寸位置
        btn.frame = CGRectMake(x, y, btnWH, btnWH);
    }
}

- (void)drawRect:(CGRect)rect {
    //如果數(shù)組當(dāng)中沒有元素,就不讓它進行繪圖.直接返回.
    if(self.selectBtn.count <= 0) return;
    //創(chuàng)建路徑.
    UIBezierPath *path = [UIBezierPath bezierPath];
    //取出所有保存的選中按鈕連線.
    for(int i = 0; i < self.selectBtn.count;i++){
        UIButton *btn = self.selectBtn[i];
        //判斷當(dāng)前按鈕是不是第一個,如果是第一個,把它的中心設(shè)置為路徑的起點.
        if(i == 0){
            //設(shè)置起點.
            [path moveToPoint:btn.center];
        }else{
            //添加一根線到當(dāng)前按鈕的圓心.
            [path addLineToPoint:btn.center];
        }
    }
    //連完先中的按鈕后, 在選中按鈕之后,添加一根線到當(dāng)前手指所在的點.
    [path addLineToPoint:self.curP];
    //設(shè)置顏色
    [[UIColor redColor] set];
    //設(shè)置線寬
    [path setLineWidth:10];
    //設(shè)置線的連接樣式
    [path setLineJoinStyle:kCGLineJoinRound];
    //繪制路徑.
    [path stroke];
}

@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容