Touch Event Handing 教學 — part 1

Jerry Wang
8 min readMar 24, 2017

--

一般來說,在iOS內,event分成三類(1)MultiTouch Events (2)Motion Events (3)Remote Control Events。在本教學中,以MultiTouch Events為主進行介紹。

不免俗的,以下官方文件還是最清楚最重要的!請大家務必詳讀

整個MultiTouch Events最主要的流程可以下圖來表達。使用者觸碰螢幕後,產生touch events,透過Gesture Recognizer識別,識別成功後,發送action message給target。

以上流程內的專有名詞,events、Gesture Recognizer、識別成功、action message、target…..分別代表的意思,將在以下內容依序講解,但看流程其實已可略知一二了。

其中,下圖分成上下兩部分,因為gesture類型分成discrete(如tap, swipe)和continuous(如pinch ),其實也是滿好理解的。

(1)使用者碰觸螢幕

使用者碰觸螢幕後,產生UITouch object(保存了觸摸的時間、位置….等相關資訊),以pinchGesture來說,需要兩根手指來完成動作,兩根手指各代表一個touch,當手指移動時,系統會更新UITouch object。

在觸碰的過程中,會經歷碰觸螢幕-> 移動 -> 離開螢幕….等,完整的觸控流程形成一個UIEvent object。一個event包含了當下使用者的所有UITouch object(ex 從第一根手指碰到螢幕開始,到最後一根手指離開螢幕)

同樣的,如下圖,手指的移動,更新UITouch object,也更新同一個UIEvent object。

一個完整的event,TouchPhase相關內容後面會詳述。

(2) Hit-Testing

產生event後,UIKit會將event加入到一個由UIApplication管理的event queue當中,UIApplication的singleton object(就是大家熟知的UIApplication.shared)從event queue中取出第一個event,傳遞給UIWindow object,按常理來說,此時UIWindow object必須將此event傳遞給任何一個能handle這個event的target,但此時尚未找到此target,因此開始了Hit-Testing。

故使用者點擊螢幕後,產生event,UIApplication接收到event後,會先調用UIWindow內的hitTest:withEvent方法,尋找被點擊到的view。

在hitTest內,會不斷呼叫pointInside函數,判斷點擊的位置是否在某個view的bound內。

關於hit-test的教學可參考下文

hitTest:withEvent返回一個UIView,調用UIWindow內的hitTest:withEvent判斷點擊是否在MainView內,若是的話返回MainView,否則返回nil。

此處必定返回MainView,若返回值不為nil的話,則會enumerate此UIView,對此UIView的subView皆呼叫其hitTest:withEvent函數。

首先UIKit調用ViewC內的hitTest:withEvent,判斷點擊是否在ViewC內,當然答案是返回nil,故ViewC1和ViewC2內的hitTest:withEvent不再調用。

接著調用ViewB的hitTest:withEvent,答案是返回ViewB,因此enumerate ViewB的subView。

最後來到了ViewB1,且ViewB1沒有subView,故可知使用者點擊的view為ViewB1,ViewB1又稱為hit-test View。

值得注意的是,在此調用hitTest:withEvent的順序是依照view的加入順序,也就是依照subViews屬性的index進行判斷。故先調用viewC接著viewB,最後才是viewA。

(3) Event傳遞

找出hit-test View後,UIApplication傳遞event給UIWindow,UIWindow傳遞event給hit-test View,讓hit-test View決定是否能handle此event,若不能handle的話,傳遞給其他的view來判斷是否能handle。

在此先解釋何謂傳遞event?為何UIApplication、UIWindow、UIView皆能傳遞event?UIApplication、UIWindow、UIView皆能傳遞event,主要是透過UIResponder。UIView繼承自UIResponder,UIApplication也繼承自UIResponder,UIWindow繼承自UIView。UIResponder不只能傳遞event,還能處理event,判斷event內各個touch的狀態,進行相對應的處理。其實如UIResponder的名稱,他可以respond event。關於UIResponder詳細的介紹將於後續繼續描述。p.s. CALayer不處理關於與使用者互動的部分。而UIView能處理與使用者互動的部分,兩者差別就在UIView繼承了UIResponder,可以響應使用者的點擊行為。

回到主題,在UIApplication中,透過sendEvent方法,傳遞event給UIWindow

UIWindow接收到event,且找到hit-test View後,透過sendEvent方法,傳遞event給hit-test View。

part 2:

par3 :

--

--