iOS-小的Demo--簡單的手勢解鎖實(shí)現(xiàn)

晴川歷歷漢陽樹,芳草萋萋鸚鵡洲!<好運(yùn)蛋>

先上效果圖:


密碼是3548

  • 開始思路分析:

前奏: 這個(gè)可以說是在簡易的畫板之上, 增加一些判斷就可以完成, 首先我們肯定需要九個(gè)圓圈的放置, 我思考的就是用九個(gè) UIView 循環(huán)的方法布置一下各自位置!
畫圖: 一個(gè)簡單的想法就是, 在九個(gè) View 所屬的大 View 畫線, 只要經(jīng)過任意一個(gè)圓圈所屬的范圍我們就把他的顏色改變, 并且記錄一下狀態(tài)(避免重復(fù)選中). 問題是第一筆如不在任一個(gè)圓圈的范圍的話, 那么我們就不能畫線, 這就是說要判斷起始點(diǎn)是否在九個(gè)圓圈的范圍中! 還有一些其他的問題我們可以遇到了在解決.
開始: 現(xiàn)在就是布局九個(gè) UIView, 每次依其中一個(gè)圓圈開始畫圖 , 觸及到一個(gè)圓圈就選中一個(gè)圓圈


上代碼解析:

// 重寫數(shù)組的 getter 方法 懶加載

- (NSMutableArray<UIBezierPath *> *)pathArray
{
    if (!_pathArray)
    {
        _pathArray = [NSMutableArray arrayWithCapacity:0];
    }
    return _pathArray;
}```

- 第 1 步:  自定義一個(gè)承載的 UIView 類 這里是 SignView 此時(shí)我們聲明幾個(gè)屬性

```code
// 在這里先定義幾個(gè)屬性
{
    // 開始是否選中了一個(gè) 圓圈  有的話 才能有下一步活動(dòng)
    BOOL _isSelectStartPoint;
    // 記錄每次 起點(diǎn)坐標(biāo)
    CGPoint _pointForBegin;
    // 記錄每次 終點(diǎn)坐標(biāo)
    CGPoint _pointForEnd;
}
#  記錄路徑的數(shù)組 用于畫圖
@property (strong, nonatomic) NSMutableArray <UIBezierPath* > *pathArray;
#  定義一個(gè)零時(shí)路徑變量  接受中間游走的路徑  這個(gè)不能放到了路徑數(shù)組里面 用于不是兩個(gè)圓圈之間的畫線
@property (strong, nonatomic) UIBezierPath *tempPath;

#  每次點(diǎn)亮一個(gè)圓圈  我就放到數(shù)組里面 記錄選中順序  組合成密碼
@property (strong, nonatomic) NSMutableArray <UIView *> *runningNumViews;

注意: 我們獲取到密碼之后, 需要告訴外界我們的密碼是多少! 當(dāng)然我們可以寫個(gè). h屬性去記錄然后到最后圖案畫好之后傳遞個(gè)需要的地方就行, 這里我寫一個(gè)協(xié)議代理方法, 當(dāng)繪制完畢之后代理人可以通過方法得到想要的數(shù)據(jù)! 稍后有體現(xiàn)!

@protocol SignViewDelegate <NSObject>
# 聲明協(xié)議方法
- (void)SingnView:(SignView *)singnView getPassWordResultWith:(NSString *)signPassWord;
@end
# .h中聲明一個(gè)屬性代理
@property (assign, nonatomic) id<SignViewDelegate> delegate;
  • 第 2 步: 構(gòu)建子視圖 也就是先把九個(gè)圓圈布局一下
- (void)createSubView
{
   
// 設(shè)置九個(gè)點(diǎn) (view) 的大小 (長寬)
    CGFloat height = 50;
    CGFloat width = 50;
// 設(shè)置九個(gè)view 的 frame 利用循環(huán)
    
    // 算一下相鄰的view的間距  左右的話留的空隙和間距一樣的空算出水平間距  算出水平的間距
    CGFloat lineSpace = (selfWIDTH -  50*3) / 4.0;
    //  豎直間距  上下留的空隙和間距一樣
    CGFloat columnSpace = (selfHEIGHT- 50*3) / 4.0;
    
    for (int i = 0 ; i< 3 ; i++)
    {
        for (int j = 0 ; j < 3 ; j++)
        {
            // 算位置 并添加
            UIView *tempView = [[UIView alloc] initWithFrame:CGRectMake(lineSpace + 50*j +lineSpace*j , columnSpace + 50*i + columnSpace*i, width, height)];
            [self addSubview:tempView];
            // 給 view 幾個(gè) tag 值加以區(qū)分 值是1000 + 1到9;
            tempView.tag = 1001 + i*3 +j;
            tempView.backgroundColor = [UIColor grayColor];
            // 切成圓形
            tempView.layer.cornerRadius = 25;
            
        }
    }
}
  • 2.1 初始化方法中布局 建立九個(gè)view表示九個(gè)大點(diǎn)
- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
     // 調(diào)用構(gòu)建視圖的方法
        [self createSubView];
    
    }
    return self;
}```

- 并列2.1 可視化編程時(shí)候   構(gòu)建子視圖

```code
- (void)awakeFromNib
{
// 調(diào)用構(gòu)建視圖方法
    [self createSubView];
}```

- 第 3 步: 在觸摸開始的方法中獲取開始點(diǎn)并且要判斷是否在九個(gè)圓圈的范圍中, 還要考慮的問題是, 第二次繪制的時(shí)候, 要在這里進(jìn)行對數(shù)據(jù)重新清空再次繪制不同任務(wù).

```code
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// 記錄密碼的數(shù)組每次都要重新去記憶添加 view
     self.runningNumViews = [NSMutableArray arrayWithCapacity:0];
//  先把存儲(chǔ)的路徑清空  第一次花圖案之后 再去畫的話  就把之前的路徑去掉
    [self.pathArray removeAllObjects];
    
// 讓九個(gè)圓圈恢復(fù)原來狀態(tài)  顏色 和是 否選中 這里用交互的值去判斷是否選中
    for (UIView *tempView in self.subviews)
    {
        tempView.userInteractionEnabled = 1;
        tempView.backgroundColor = [UIColor grayColor];
    }
    
// 獲取觸摸的第一個(gè)為開始點(diǎn)
    _pointForBegin = [touches.anyObject locationInView:self];
    
// 遍歷檢查一下開始點(diǎn)是否是在 九個(gè)圓圈中某一個(gè)的范圍中
    for (UIView *subView in self.subviews)
    {
        if (CGRectContainsPoint(subView.frame, _pointForBegin))
        {
            // 若是在 改變圓圈顏色
            subView.backgroundColor = [UIColor greenColor];
            // 記錄一下有沒有開始點(diǎn)
            _isSelectStartPoint = 1;
            // 更改開始點(diǎn)的坐標(biāo)
            _pointForBegin = subView.center;
            // 用 view 的交互去記錄是否選中
            subView.userInteractionEnabled = 0;
            [self.runningNumViews addObject:subView];
        }
    }

}
  • 第 4 步: 在移動(dòng)的過程中 我們需要不斷的獲取終點(diǎn)畫直線 , 當(dāng)這個(gè)移動(dòng)點(diǎn)移動(dòng)到九個(gè)圓圈的范圍之內(nèi)的時(shí)候我們就把圓圈點(diǎn)亮, 并且要重新繪制直線以圓圈的中點(diǎn)為一個(gè)點(diǎn)和起始的圓圈中心點(diǎn)連線.具體參看代碼
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// 獲取移動(dòng)中的終點(diǎn)
    _pointForEnd = [touches.anyObject locationInView:self];

// 看看有沒有開始的圓圈被選中要是有的話才會(huì)有一系列的操作  否則不管
    if (_isSelectStartPoint)
    {
    // 創(chuàng)建一個(gè)臨時(shí)的路徑再說
        self.tempPath = [UIBezierPath bezierPath];
    // 設(shè)置路徑起點(diǎn)
        [self.tempPath moveToPoint:_pointForBegin];
    // 移動(dòng)中的臨時(shí)終點(diǎn)線連起來
        [self.tempPath addLineToPoint:_pointForEnd ];
    
    // 判斷終點(diǎn)是否在  九個(gè)圓圈的范圍中
         for (UIView *subView in self.subviews)
   
         {
             if (CGRectContainsPoint(subView.frame, _pointForEnd) && subView.userInteractionEnabled)
             {
            // 改變顏色 并關(guān)閉 交互 表示選中了
                 subView.backgroundColor = [UIColor colorWithRed:(arc4random()%345)/346.0 green:(arc4random()%345)/346.0   blue:(arc4random()%345)/346.0 alpha: 1];
                 subView.userInteractionEnabled = 0;
                 [self.runningNumViews addObject:subView];
            // 重新規(guī)劃路徑
                 self.tempPath = [UIBezierPath new];
                 [self.tempPath moveToPoint:_pointForBegin];
                 [self.tempPath addLineToPoint:subView.center];
            // 把路徑存放到數(shù)組中
                 [self.pathArray addObject:self.tempPath];
                 
            // 為找下一個(gè)圓圈位置做準(zhǔn)備  要以這個(gè)選中圓圈位置中心開始點(diǎn)
                 _pointForBegin = subView.center;
             }
    
         }

    }
// 不要忘了  去渲染繪制一下
    [self setNeedsDisplay];
}
  • 第 5 步: 當(dāng)我們觸摸結(jié)束的時(shí)候, 要把多余的線條去掉 (不是連接兩個(gè)圓圈的線條) 而且移動(dòng)結(jié)束也意味著輸入密碼的結(jié)束! 我們外界可以通過代理方法得到當(dāng)前這次繪制的密碼.
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// 清除當(dāng)前的路徑  目的是 把多余的沒有連接兩個(gè)圈的線 去掉
    self.tempPath = nil;
// 設(shè)置沒有選中開始點(diǎn) 為下一次繪制做準(zhǔn)備
    _isSelectStartPoint = 0;
// 繪制渲染一下
    [self setNeedsDisplay];
    
    NSMutableString *resulet = [NSMutableString string];
   // 可用 tag 值 依據(jù)數(shù)組中放入 view 的順序得到密碼.
    for (UIView *tempView in self.runningNumViews)
    {
        [resulet appendFormat:@"%ld",tempView.tag - 1000];
    }
  // 這里去調(diào)用代理方法  向外界傳遞繪制的結(jié)果  
    if (resulet && ![resulet isEqualToString:@""])
    {
         [self.delegate SingnView:self getPassWordResultWith:resulet];
    }
}
  • 第 6 步: 關(guān)鍵一步, 那就是繪制方法的完善
// 重新繪圖
- (void)drawRect:(CGRect)rect
{
// 找到所有連接兩個(gè)圓圈的路徑  渲染
    for (UIBezierPath *path in self.pathArray)
    {
        [path setLineWidth:6];
        [[UIColor redColor] set];
        [path stroke];
    }
// 臨時(shí)路徑渲染
    self.tempPath.lineWidth = 6;
    [[UIColor blueColor] set];
    [self.tempPath stroke];

}
  • 最后 1 步: 在ViewController 中使用這個(gè) SignView 遵循他的代理<SignViewDelegate>并實(shí)現(xiàn)方法即可:
- (void)SingnView:(SignView *)singnView getPassWordResultWith:(NSString *)signPassWord
{
    NSLog(@"-------->%@",signPassWord);
    if ([signPassWord isEqualToString:@"3548"])
    {
        [UIView animateWithDuration:1 animations:^{
            self.signView.frame = CGRectMake(0, self.view.bounds.size.height, 0, 0);
        } completion:^(BOOL finished) {
            self.signView = nil;
        }];
        
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 在iOS中隨處都可以看到絢麗的動(dòng)畫效果,實(shí)現(xiàn)這些動(dòng)畫的過程并不復(fù)雜,今天將帶大家一窺ios動(dòng)畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,573評論 6 30
  • 轉(zhuǎn)載:http://www.lxweimin.com/p/32fcadd12108 每個(gè)UIView有一個(gè)伙伴稱為l...
    F麥子閱讀 6,321評論 0 13
  • >復(fù)雜的組織都是專門化的 >Catharine R. Stimpson 到目前為止,我們已經(jīng)探討過`CALayer...
    夜空下最亮的亮點(diǎn)閱讀 1,085評論 0 2
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫效果,實(shí)現(xiàn)這些動(dòng)畫的過程并不復(fù)雜,今天將帶大家一窺iOS動(dòng)畫全貌。在這里你可以看...
    F麥子閱讀 5,147評論 5 13
  • 每個(gè)UIView有一個(gè)伙伴稱為layer,一個(gè)CALayer。UIView實(shí)際上并沒有把自己畫到屏幕上;它繪制本身...
    shenzhenboy閱讀 3,160評論 0 17