深入淺出iOS事件機制

本文章將講解有關iOS事件的傳遞機制,如有錯誤或者不同的見解,歡迎留言指出。

iOS的事件有好幾種:Touch Events(觸摸事件)、Motion Events(運動事件,比如重力感應和搖一搖等)、Remote Events(遠程事件,比如用耳機上得按鍵來控制手機),其中最常用的應該就是Touch Events了,基本存在于每個app的每個地方,今天我們主要就講講它,至于其他兩個事件有興趣的可以自行查閱資料。

在網頁上當我們講到事件,我們會講到事件響應鏈,我們會講到事件的響應者和事件的傳遞方式(冒泡),那么在app上,其實也離不開這幾個問題,今天我們也重這幾個方面來介紹iOS的事件機制: 1、響應鏈是什么時候怎樣構建的? 2、事件第一個響應者是怎么確定的? 3、事件第一個響應者確定后,系統是怎樣傳遞事件的?

響應鏈的構建

無論是哪種事件,其傳遞和響應都與響應鏈息息相關,那么響應鏈到底是一個什么樣的東西呢? 在UIKit中有一個類:UIResponder,我們可以看看頭文件的幾個屬性和方法:

iosevent_1.png

UIResponder是所有可以響應事件的類的基類(從名字應該就可以看出來了),其中包括最常見的UIView和UIViewController甚至是UIApplication,所以我們的UIView和UIViewController都是作為響應事件的載體。

那么響應鏈跟這個UIResponder有什么關系呢?事實事件響應鏈的形成和事件的響應和傳遞,UIResponder都幫我們做了很多事。我們的app中,所有的視圖都是按照一定的結構組織起來的,即樹狀層次結構,每個view都有自己的superView,包括controller的topmost view(controller的self.view)。當一個view被add到superView上的時候,他的nextResponder屬性就會被指向它的superView,當controller被初始化的時候,self.view(topmost view)的nextResponder會被指向所在的controller,而controller的nextResponder會被指向self.view的superView,這樣,整個app就通過nextResponder串成了一條鏈,也就是我們所說的響應鏈。所以響應鏈就是一條虛擬的鏈,并沒有一個對象來專門存儲這樣的一條鏈,而是通過UIResponder的屬性串連起來的。如下圖:

iosevent_2.png
iosevent_3.png
Hit-Testing View

文章開頭說到有iOS三種event類型,事件傳遞中UIWindow會根據不同的event,用不同的方式尋找initial object,initial object決定于當前的事件類型。比如Touch Event,UIWindow會首先試著把事件傳遞給事件發生的那個view,就是下文要說的hit-testview。對于Motion和Remote Event,UIWindow會把例如震動或者遠程控制的事件傳遞給當前的firstResponder,有關firstResponder的相關信息請看這里。下面主要講Touch Event的hit-testview。

有了事件響應鏈,接下來的事情就是尋找響應事件的具體響應者了,我們稱著為:Hit-Testing View,尋找這個View的過程我們稱著為Hit-Test。

那么什么是Hit-Test呢,我們可以把它理解為一個探測器,通過這個探測器我們可以找到并判斷手指是否點擊在某個視圖上面,換句話說就是通過Hit-Test可以找到手指點擊到的處于屏幕最前面的那個UIView。

在解釋Hit-Test是怎么工作之前,先來看看它是什么時候被調用的。前面說Hit-Test是一個探測器,那么在代碼里面其實就是一個函數,UIView有如下兩個方法:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; 
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;

每當手指接觸屏幕,UIApplication接收到手指的事件之后,就會去調用UIWindow的hitTest:withEvent:,看看當前點擊的點是不是在window內,如果是則繼續依次調用subView的hitTest:withEvent:方法,直到找到最后需要的view。調用結束并且hit-test view確定之后,這個view和view上面依附的手勢,都會和一個UITouch的對象關聯起來,這個UITouch會作為事件傳遞的參數之一,我們可以看到UITouch頭文件里面有一個view和gestureRecognizers的屬性,就是hitTest view和它的手勢。

現在知道Hit-Test是什么時候調用了,那么接下來看看它是怎么工作的。Hit-Test是采用遞歸的方法從view層級的根節點開始遍歷,看看下面這張圖:

由于排版原因,直接原文鏈接:

http://zhoon.github.io/ios/2015/04/12/ios-event.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容