????? 手勢(shì)解鎖這樣的例子網(wǎng)上很多镊绪。對(duì)于新手而言夹攒,如果對(duì)iOS不是很熟悉,做這樣的功能有一種無從下手的感覺邮府,主要是因?yàn)槟承┘?xì)節(jié)看起來不好實(shí)現(xiàn)荧关。我平時(shí)在開發(fā)項(xiàng)目的時(shí)候,一般遵循一個(gè)原則就是褂傀,先詳細(xì)分析忍啤,把整個(gè)邏輯理清楚,先不管看起來多么難仙辟,一個(gè)一個(gè)的細(xì)節(jié)剝離開來同波,然后開始構(gòu)思,最好是越簡(jiǎn)單越好叠国,條理性越清楚越好参萄。我最初學(xué)習(xí)iOS的時(shí)候,當(dāng)時(shí)很想做一個(gè)手勢(shì)解鎖這樣的功能煎饼,但是因?yàn)楫?dāng)時(shí)對(duì)iOS開發(fā)不熟悉讹挎,嘗試了很多復(fù)雜的方式,但是總是不是很完美∵壕粒現(xiàn)在就采用一種簡(jiǎn)單地方式來實(shí)現(xiàn)一個(gè)手勢(shì)解鎖組件筒溃。這是我目前想到的最簡(jiǎn)單的方法。
先看一下具體的效果圖:
下面我先詳細(xì)分析一下沾乘,具體的實(shí)現(xiàn)方式:
1.實(shí)現(xiàn)3行3列排布圓形怜奖,每個(gè)圓之間的間距相等,總體擺勻稱就行了(這里涉及到一些坐標(biāo)運(yùn)算)翅阵。
2.截獲用戶手指在屏幕上滑動(dòng)的事件歪玲,然后根據(jù)滑動(dòng)的具體坐標(biāo)繪制折線(請(qǐng)?jiān)试S我把這些連接起來的線稱為折線)。
3.觸摸手指離開屏幕時(shí)掷匠,清除所有的繪制圖案滥崩。
這里有個(gè)比較棘手的細(xì)節(jié)不好處理,簡(jiǎn)單歸納如下:
如果某個(gè)點(diǎn)已經(jīng)被連過讹语,那么下次再次移動(dòng)到此點(diǎn)上的時(shí)候钙皮,不能再重復(fù)連線。
現(xiàn)在我們開始分析前面所述的三個(gè)步驟如何實(shí)現(xiàn):
1.這里的圓形顽决,我們觀察到短条,有兩種狀態(tài),一種是發(fā)光的才菠,一種是不發(fā)光的茸时。我最初剛開始看到這樣的效果的效果的時(shí)候,我直觀的使用繪圖的方式繪制了9個(gè)圓形赋访,但這樣思考問題的時(shí)候可都,很顯然感覺到異常復(fù)雜缓待,僅僅是處理圓形的兩種狀態(tài)就已經(jīng)很讓人頭痛了。這里汹粤,我們直接創(chuàng)建9個(gè)按鈕命斧,然后設(shè)置不同狀態(tài)的圖片即可田晚。所以我們?cè)诔跏蓟椒ɡ锩鎰?chuàng)建9個(gè)button嘱兼,并添加到父視圖。這里最好對(duì)按鈕做一些封裝贤徒,屏蔽一些細(xì)節(jié)芹壕,讓總體的代碼更加簡(jiǎn)潔。這里我繼承UIButton類接奈,實(shí)現(xiàn)了一個(gè)名為HGCircleView的類踢涌。在后面創(chuàng)建的時(shí)候,我們直接引用這個(gè)類:
\\在initWithFrame方法里面實(shí)現(xiàn)如下的代碼 創(chuàng)建圓形
??? for (NSUInteger i = 0; i < COL_COUNT * ROW_COUNT; ++i) {
??????? HGCircleView* circleView = [HGCircleView circleView];
??????? [self addSubview:circleView];
??? }
2.主要的邏輯就在于第2步了序宦,當(dāng)用戶在屏幕上移動(dòng)觸摸點(diǎn)的時(shí)候睁壁,我們要追蹤到移動(dòng)的軌跡,然后繪制折線互捌。
首先潘明,要追蹤用戶觸摸的軌跡,我們需要重寫三個(gè)方法:
touchesBegan秕噪、touchesMoved钳降、touchesEnded
這三個(gè)方法里面我們可以記錄下用戶最初按壓時(shí)的點(diǎn),移動(dòng)過程中的當(dāng)前點(diǎn)腌巾,以及手指離開時(shí)的點(diǎn)遂填。
在這里,先不要急于繪制移動(dòng)的路徑澈蝙。最終的目的是要把所有觸摸軌跡經(jīng)過的圓形串起來并生成密碼吓坚。所以我在這里用一個(gè)容器,保存了路徑經(jīng)過的所有的circleView灯荧。這里處理一個(gè)細(xì)節(jié)就是凌唬,當(dāng)觸摸到圓形的時(shí)候,我們?cè)O(shè)置圓形的狀態(tài)是selected.并在circleView類的內(nèi)部設(shè)置好selected狀態(tài)下漏麦,顯示發(fā)光效果的圖片客税。
這里順便就可以處理前面提到的那個(gè)比較棘手的細(xì)節(jié),在手勢(shì)經(jīng)過圓形的時(shí)候撕贞,先做一個(gè)檢查更耻,如果發(fā)現(xiàn)圓形已經(jīng)處于selected狀態(tài),那么捏膨,就不在把圓形加入容器秧均,這樣就不會(huì)重復(fù)選擇食侮,很輕松就解決了那個(gè)問題。
接下來目胡,在drawRect方法里面繪制觸摸軌跡锯七,遍歷容器,然后把所有的圓形的center加入U(xiǎn)IBezierPath誉己,然后繪制UIBezierPath即可眉尸。
這樣會(huì)出現(xiàn)一個(gè)新的問題,就是巨双,當(dāng)觸摸移動(dòng)到其他位置(不在圓形上)噪猾,這個(gè)時(shí)候,不能同步繪制筑累,這里我采取的處理方式是袱蜡,用一個(gè)點(diǎn)記錄當(dāng)前用戶手指觸摸移動(dòng)的位置,然后把這個(gè)點(diǎn)作為最后一個(gè)點(diǎn)加入到UIBezierPath中慢宗,為了保證這個(gè)點(diǎn)的可靠性坪蚁,在每次按壓屏幕的時(shí)候?qū)⑦@個(gè)點(diǎn)置為(-10, -10)镜沽,并且在添加到UIBezierPath路徑之前檢查一下敏晤,如果不是(-10, -10)則加入路徑淘邻。
// 1.容器為空茵典,不執(zhí)行任何繪制?
? if (0 == self.circleViews.count) {
??????? return;
??? }
???
??? UIBezierPath* bezierPath = [UIBezierPath new];
??? [bezierPath moveToPoint: [[self.circleViews firstObject] center]];
??? for (NSUInteger i = 1; i < self.circleViews.count; ++i) {
??????? [bezierPath addLineToPoint:[[self.circleViews objectAtIndex:i] center]];
??? }
???
??? if (NO == CGPointEqualToPoint(self.curlastPoint, CGPointMake(-10.0f, -10.0f))) {
??????? [bezierPath addLineToPoint:self.curlastPoint];
??? }
??? // 2.設(shè)置線形
??? bezierPath.lineWidth = 7;
??? bezierPath.lineJoinStyle = kCGLineJoinBevel;
??? [[UIColor colorWithRed:36/255.0 green:200/255.0 blue:260/255.0 alpha:0.5]? set];???????// 3.繪制路徑?
?? [bezierPath stroke];
3.手指觸摸彈起來的時(shí)候,需要清空繪制宾舅,這個(gè)時(shí)候统阿,這需要清空保存所有被選擇circleView的容器即可。注意在清空之前筹我,應(yīng)該先利用容器內(nèi)的圓形的相關(guān)信息生成密碼扶平。并且把所有圓形的狀態(tài)置為Normal狀態(tài)。
????? 上述這些步驟即可以完成一個(gè)手勢(shì)解鎖功能蔬蕊。好了结澄,說了半天,也沒有用上手勢(shì)識(shí)別器岸夯,僅僅處理了三個(gè)事件麻献。你可以下載詳細(xì)代碼參考。
???? 詳細(xì)代碼實(shí)現(xiàn)github地址:點(diǎn)擊這里下載?
????