對iOS用戶來說,他們操作設(shè)備的動作主要分為三種:觸摸屏幕敞恋、晃動設(shè)備以及通過遙控設(shè)施控制設(shè)備丽啡,事件響應(yīng)鏈主要是針對觸摸屏幕來說的。事件響應(yīng)鏈?zhǔn)怯梢幌盗胁煌瑢ο蠼M成的層次結(jié)構(gòu)耳舅,其中的每個對象都能夠獲得響應(yīng)事件的機(jī)會碌上。
在iOS中,一個對象想要響應(yīng)事件浦徊,那么它必須是UIResponder的子類馏予,我們熟悉的UIApplication,UIWindow,UIViewController,UIView都可以響應(yīng)事件。響應(yīng)者鏈通常都是由View組成盔性。當(dāng)點(diǎn)擊了某一個視圖的時候會產(chǎn)生一個點(diǎn)擊事件霞丧,這個事件會被加入由UIApplication管理的事件隊(duì)列,當(dāng)輪到它的時候UIApplication會把此事件分配給當(dāng)前顯示的UIWindow,UIWindow會在它本身以及子視圖里來尋找合適的響應(yīng)者來處理這個事件冕香。這個合適的響應(yīng)者就是我們常稱的第一響應(yīng)者蛹尝。在尋找第一響應(yīng)者的時候其實(shí)一直在調(diào)用hitTest:withEvent:方法后豫,這個方法的作用是來尋找一個合適的視圖來處理事件。但是在hitTest:withEvent方法內(nèi)部又調(diào)用了一個方法pointInside:withEvent突那,它的作用是判斷當(dāng)前點(diǎn)擊的位置在不在這個視圖內(nèi)挫酿,如果不在返回NO,對應(yīng)的hitTest:withEvent返回nil愕难,如果在繼續(xù)遍歷當(dāng)前視圖的子視圖早龟,直到找到第一響應(yīng)者。
在這個視圖結(jié)構(gòu)中猫缭,當(dāng)我們點(diǎn)擊了黃色的View的時候葱弟,UIApplication會先將事件傳遞給UIWindow,然后判斷點(diǎn)擊的位置是不是在UIWindow里面,再然后遍歷它的子視圖猜丹,看點(diǎn)擊的位置在哪個子視圖(此圖只有一個子視圖即紅色的試圖)芝加,以此類推最后找到黃色的視圖。此時黃色的視圖是第一響應(yīng)者射窒,藍(lán)色的是第二響應(yīng)者藏杖,紅色的是第三響應(yīng)者,控制器是第四響應(yīng)者轮洋,UIWindow是第五響應(yīng)者制市,事件最后會被傳遞給UIApplication,如果UIApplication不對事件進(jìn)行處理那么事件會被丟棄弊予。(在尋找第一響應(yīng)者的時候順序是從上到下,但是在對事件進(jìn)行處理的時候順序是從下到上)
根據(jù)尋找第一響應(yīng)者的方法即hitTest:withEvent我們可以修改這個方法從而修改第一響應(yīng)者开财,但是不建議這么做汉柒,因?yàn)檫@樣做可能會導(dǎo)致某些奇怪的BUG,當(dāng)我們在調(diào)試程序的時候會非常難找责鳍,如果真的不想第一響應(yīng)者對事件進(jìn)行處理可以用代理讓別的響應(yīng)者來處理這個事情碾褂。另外我們還需要注意一件事情,事件會響應(yīng)發(fā)生在這3種情況下:
- 視圖沒有隱藏
- 視圖的透明度不低于0.01
3.視圖可以接受事件(即userInteractionEnabled為YES)
當(dāng)我們某個父視圖的條件不滿足上面的三個條件的任何一種情況历葛,那么它和它上面的所有的子視圖是不會接受事件的(因?yàn)閔itTest:withEvent走到父視圖直接就返回了也不會去遍歷父視圖里面的子視圖)正塌,所以我們某些情況下會看到我們明明點(diǎn)擊了某一個視圖,但是卻不是我們需要的效果恤溶,或者它下面的某一個視圖做出了響應(yīng)乓诽,此時我們不妨看看它或者它的父視圖有沒有滿足上面這三個條件。