既然要說觸摸和手勢(shì)的區(qū)別和聯(lián)系,那咱們就需要先講一下觸摸和手勢(shì)的定義。
觸摸:
這個(gè)通過名字就知道,就是我們的手指觸碰到屏幕的事件就可以稱為觸摸。當(dāng)發(fā)生觸摸事件的時(shí)候默認(rèn)是沒有響應(yīng)動(dòng)作的。在iOS系統(tǒng)中,能夠響應(yīng)并處理事件的對(duì)象稱之為responder object, UIResponder是所有responder對(duì)象的基類,在UIResponder類中定義了處理各種事件,處理觸摸事件的編程接口如下:
– touchesBegan:withEvent:
– touchesMoved:withEvent:
– touchesEnded:withEvent:
– touchesCancelled:withEvent:
這四個(gè)方法分別處理觸摸開始事件,觸摸移動(dòng)事件,觸摸終止事件,以及觸摸跟蹤取消事件。只有重載UIResponder的這些方法才能實(shí)現(xiàn)觸摸事件的響應(yīng)。
說到觸摸事件的響應(yīng),肯定繞不過去響應(yīng)者鏈。響應(yīng)者鏈就是一系列連接的responder對(duì)象。UIApplication, UIViewController,UIView和所有繼承自UIView的UIKit類(包括UIWindow,繼承自UIView)都直接或間接的繼承自UIResponder,所以它們的實(shí)例都是responder object對(duì)象,都實(shí)現(xiàn)了上述4個(gè)方法。UIResponder中的默認(rèn)實(shí)現(xiàn)是什么都不做,但UIKit中UIResponder的直接子類(UIView,UIViewController…)的默認(rèn)實(shí)現(xiàn)是將事件沿著responder chain繼續(xù)向上傳遞到下一個(gè)responder,即nextResponder。
iOS中responder chain的結(jié)構(gòu)為:

Paste_Image.png
UIView的nextResponder屬性,如果有管理此view的UIViewController對(duì)象,則為此UIViewController對(duì)象;否則nextResponder即為其superview。
UIViewController的nextResponder屬性為其管理view的superview.
UIWindow的nextResponder屬性為UIApplication對(duì)象。
UIApplication的nextResponder屬性為nil。
iOS中發(fā)生觸摸事件的時(shí)候(當(dāng)發(fā)生觸摸事件的時(shí)候會(huì)把這個(gè)事件給到UIApplication專門處理觸摸事件的一個(gè)隊(duì)列里,個(gè)人臆測(cè),如有錯(cuò)誤請(qǐng)指正)APP就開始了尋找發(fā)生觸摸的視圖的過程,這個(gè)尋找的的順序是從底向上的過程。首先UIApplication會(huì)傳遞給UIWindow,然后再由UIWindow傳遞給頂級(jí)的視圖,頂級(jí)視圖會(huì)進(jìn)一步遍歷其所有的subviews。UIView有個(gè)函數(shù)叫hitTest,如果觸摸事件是發(fā)生在該視圖中,則該函數(shù)會(huì)返回非空UIView;然后該視圖遞歸其subviews,最后發(fā)現(xiàn)最終的subview。iOS系統(tǒng)在處理事件時(shí),通過UIApplication對(duì)象和每個(gè)UIWindow對(duì)象的sendEvent:方法將事件分發(fā)給具體處理此事件的responder對(duì)象,當(dāng)具體處理此事件的responder不處理此事件時(shí),可以通過responder chain交給上一級(jí)處理。基本的觸摸響應(yīng)的過程就先介紹到這。下面咱們來說一下手勢(shì)。
手勢(shì)
手勢(shì)相比觸碰事件的好處是可以直接使用已經(jīng)定義好的手勢(shì),開發(fā)者不用自己計(jì)算手指移動(dòng)軌跡。缺點(diǎn)就是沒辦法自定義手勢(shì),只能用系統(tǒng)已經(jīng)實(shí)現(xiàn)的手勢(shì)。如果想實(shí)現(xiàn)自己發(fā)明的某種手勢(shì)還得去用觸摸。手勢(shì)識(shí)別的基類是UIGestureRecognizer,是一個(gè)抽象類,定義了實(shí)現(xiàn)底層手勢(shì)識(shí)別行為的編程接口。衍生類如下:
UITabGestureRecognizer? ? ? ? 輕擊手勢(shì)
UIPinchGestureRecognizer? ? ? 捏合手勢(shì)
UIRotationGestureRecognizer? ? 旋轉(zhuǎn)手勢(shì)
UISwipeGestureRecognizer? 輕掃手勢(shì)
UIPanGestureRecognizer 拖拽手勢(shì)
UILongPressGestrueRecognizer 長(zhǎng)按手勢(shì)
使用手勢(shì)很簡(jiǎn)單,分為兩步:
創(chuàng)建手勢(shì)實(shí)例。當(dāng)創(chuàng)建手勢(shì)時(shí),指定一個(gè)回調(diào)方法,當(dāng)手勢(shì)開始,改變、或結(jié)束時(shí),回調(diào)方法被調(diào)用。
添加到需要識(shí)別的View中。每個(gè)手勢(shì)只對(duì)應(yīng)一個(gè)View,當(dāng)屏幕觸摸在View的邊界內(nèi)時(shí),如果手勢(shì)和預(yù)定的一樣,那就會(huì)回調(diào)方法。
我們用點(diǎn)擊手勢(shì)舉個(gè)例子:
UITapGestureRecognizer *single = [[UITapGestureRsecognizer alloc] initWithTarget:self action:@selector(singlEvent:)];
single.delegate = self;
[self.view addGestureRecognizer: single];
一個(gè)手勢(shì)只能對(duì)應(yīng)一個(gè)View,但是一個(gè)View可以有多個(gè)手勢(shì)。如果View添加了多個(gè)手勢(shì),缺省情況下,沒有對(duì)手勢(shì)的執(zhí)行順序排序,每次調(diào)用順序可能都不同。通過以下方法可以控制手勢(shì)的響應(yīng)順序。
(void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer
手勢(shì)雖然也是封裝的觸摸事件,當(dāng)發(fā)生手勢(shì)時(shí)不會(huì)觸發(fā)響應(yīng)者鏈的響應(yīng)過程,當(dāng)前的view會(huì)先攔截這個(gè)觸摸事件,然后查看是否實(shí)現(xiàn)了相關(guān)的手勢(shì)。如果有相應(yīng)的手勢(shì)就響應(yīng)手勢(shì),如果沒有才會(huì)加到觸摸的響應(yīng)者鏈里,開始觸摸事件的響應(yīng)過程。
更多手勢(shì)相關(guān)的說明請(qǐng)看官方文檔:uigesturerecognizer
說道手勢(shì)不得不說的就是UIGestureRecognizerDelegate。在此呢我只想說跟主題相關(guān)的一個(gè)代理函數(shù):
(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
此方法在window對(duì)象有觸碰事件發(fā)生時(shí),touchesBegan:withEvent:方法之前調(diào)用。如果返回NO,則GestureRecognizer忽略此觸碰事件。默認(rèn)返回YES??梢杂糜诮鼓硞€(gè)區(qū)域的手勢(shì)。
其他的請(qǐng)見官方說明:uigesturerecognizerdelegate
總結(jié):
簡(jiǎn)單總結(jié)一下吧,手勢(shì)和觸摸歸根到底是同一個(gè)事件,只不過響應(yīng)的過程不同。手勢(shì)是通過代理函數(shù)處理響應(yīng)過程的,而觸摸通過響應(yīng)者鏈處理。歡迎大家評(píng)論區(qū)討論,有什么說的不對(duì)的地方也請(qǐng)指正,謝謝。