事件響應鏈

對iOS用戶來說,他們操作設備的動作主要分為三種:觸摸屏幕、晃動設備以及通過遙控設施控制設備,事件響應鏈主要是針對觸摸屏幕來說的。事件響應鏈是由一系列不同對象組成的層次結構,其中的每個對象都能夠獲得響應事件的機會。

在iOS中,一個對象想要響應事件,那么它必須是UIResponder的子類,我們熟悉的UIApplication,UIWindow,UIViewController,UIView都可以響應事件。響應者鏈通常都是由View組成。當點擊了某一個視圖的時候會產生一個點擊事件,這個事件會被加入由UIApplication管理的事件隊列,當輪到它的時候UIApplication會把此事件分配給當前顯示的UIWindow,UIWindow會在它本身以及子視圖里來尋找合適的響應者來處理這個事件。這個合適的響應者就是我們常稱的第一響應者。在尋找第一響應者的時候其實一直在調用hitTest:withEvent:方法,這個方法的作用是來尋找一個合適的視圖來處理事件。但是在hitTest:withEvent方法內部又調用了一個方法pointInside:withEvent,它的作用是判斷當前點擊的位置在不在這個視圖內,如果不在返回NO,對應的hitTest:withEvent返回nil,如果在繼續遍歷當前視圖的子視圖,直到找到第一響應者。

屏幕快照 2016-09-21 21.47.50.png

在這個視圖結構中,當我們點擊了黃色的View的時候,UIApplication會先將事件傳遞給UIWindow,然后判斷點擊的位置是不是在UIWindow里面,再然后遍歷它的子視圖,看點擊的位置在哪個子視圖(此圖只有一個子視圖即紅色的試圖),以此類推最后找到黃色的視圖。此時黃色的視圖是第一響應者,藍色的是第二響應者,紅色的是第三響應者,控制器是第四響應者,UIWindow是第五響應者,事件最后會被傳遞給UIApplication,如果UIApplication不對事件進行處理那么事件會被丟棄。(在尋找第一響應者的時候順序是從上到下,但是在對事件進行處理的時候順序是從下到上)

根據尋找第一響應者的方法即hitTest:withEvent我們可以修改這個方法從而修改第一響應者,但是不建議這么做,因為這樣做可能會導致某些奇怪的BUG,當我們在調試程序的時候會非常難找,如果真的不想第一響應者對事件進行處理可以用代理讓別的響應者來處理這個事情。另外我們還需要注意一件事情,事件會響應發生在這3種情況下:

  1. 視圖沒有隱藏
  2. 視圖的透明度不低于0.01
    3.視圖可以接受事件(即userInteractionEnabled為YES)
    當我們某個父視圖的條件不滿足上面的三個條件的任何一種情況,那么它和它上面的所有的子視圖是不會接受事件的(因為hitTest:withEvent走到父視圖直接就返回了也不會去遍歷父視圖里面的子視圖),所以我們某些情況下會看到我們明明點擊了某一個視圖,但是卻不是我們需要的效果,或者它下面的某一個視圖做出了響應,此時我們不妨看看它或者它的父視圖有沒有滿足上面這三個條件。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 好奇觸摸事件是如何從屏幕轉移到APP內的?困惑于Cell怎么突然不能點擊了?糾結于如何實現這個奇葩響應需求?亦或是...
    Lotheve閱讀 57,871評論 51 603
  • 本文來自:http://ios.jobbole.com/84081/ 前言: 按照時間順序,事件的生命周期是這樣的...
    HackerOnce閱讀 2,858評論 1 10
  • 在iOS開發中經常會涉及到觸摸事件。本想自己總結一下,但是遇到了這篇文章,感覺總結的已經很到位,特此轉載。作者:L...
    WQ_UESTC閱讀 6,094評論 4 26
  • App通過響應者對象來接收和處理事件,響應者對象都是UIResponder的子類對象,常見的UIView,UIVi...
    FlyElephant閱讀 1,255評論 0 5
  • 最近比較忙,壓力也大,越是壓力大的時候越應該停下來審視一下自己。 題目涉及到了三個名詞,分別是壓力、焦慮和拖延癥。...
    GeekPlux閱讀 1,396評論 0 2