iOS-小的Demo--簡單的手勢(shì)解鎖實(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)行對(duì)數(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)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末劳景,一起剝皮案震驚了整個(gè)濱河市盟猖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌钩骇,老刑警劉巖乎婿,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件满败,死亡現(xiàn)場(chǎng)離奇詭異楔壤,居然都是意外死亡拷况,警方通過查閱死者的電腦和手機(jī)找爱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門梗顺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人车摄,你說我怎么就攤上這事寺谤。” “怎么了吮播?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵变屁,是天一觀的道長。 經(jīng)常有香客問我意狠,道長粟关,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任环戈,我火速辦了婚禮闷板,結(jié)果婚禮上澎灸,老公的妹妹穿的比我還像新娘。我一直安慰自己遮晚,他們只是感情好性昭,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著县遣,像睡著了一般糜颠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上萧求,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天其兴,我揣著相機(jī)與錄音,去河邊找鬼饭聚。 笑死忌警,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的秒梳。 我是一名探鬼主播法绵,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼酪碘!你這毒婦竟也來了朋譬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤兴垦,失蹤者是張志新(化名)和其女友劉穎徙赢,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體探越,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡狡赐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了钦幔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枕屉。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖鲤氢,靈堂內(nèi)的尸體忽然破棺而出搀擂,到底是詐尸還是另有隱情,我是刑警寧澤卷玉,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布哨颂,位于F島的核電站,受9級(jí)特大地震影響相种,放射性物質(zhì)發(fā)生泄漏威恼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望沃测。 院中可真熱鬧缭黔,春花似錦、人聲如沸蒂破。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽附迷。三九已至惧互,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間喇伯,已是汗流浹背喊儡。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留稻据,地道東北人艾猜。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像捻悯,于是被迫代替她去往敵國和親匆赃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

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

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