iOS事件傳遞、響應(yīng)者鏈、hitTest、pointInside

一、什么是事件傳遞

發(fā)生觸摸事件后,系統(tǒng)會(huì)將該事件加入到一個(gè)由UIApplication管理的事件隊(duì)列中,并將事件分發(fā)下去以便處理。通常,會(huì)先發(fā)送事件給應(yīng)用程序的keyWindow,主窗口會(huì)在其視圖層次結(jié)構(gòu)中找到一個(gè)最合適的視圖來處理觸摸事件,這個(gè)找尋的過程就是事件傳遞

二、事件傳遞的過程

  • 1.事件傳遞的方向。
    window -> 父視圖 -> 子視圖 - >子視圖的子視圖
    我們可以這個(gè)方向簡單理解成從內(nèi)到外

  • 2.兩個(gè)關(guān)鍵函數(shù)
    首先我們先來了解兩個(gè)系統(tǒng)函數(shù)。
    1.pointInside:withEvent:

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

    這個(gè)方法是UIView用來判斷點(diǎn)擊事件發(fā)生的位置是否在當(dāng)前視圖范圍內(nèi)。

    2.hitTest:withEvent:

    // point是該視圖的坐標(biāo)系上的點(diǎn)
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    {
      // 1.判斷自己能否接收觸摸事件
      if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil;
      // 2.判斷觸摸點(diǎn)在不在自己范圍內(nèi)
      if (![self pointInside:point withEvent:event]) return nil;
      // 3.從后往前遍歷自己的子控件,看是否有子控件更適合響應(yīng)此事件
      int count = self.subviews.count;
      for (int i = count - 1; i >= 0; i--) {
          UIView *childView = self.subviews[i];
          CGPoint childPoint = [self convertPoint:point toView:childView];
          UIView *fitView = [childView hitTest:childPoint withEvent:event];
          if (fitView) {
              return fitView;
          }
      }
      // 沒有找到比自己更合適的view
      return self;
    }
    
    

    以上是hitTest:withEvent:的底層實(shí)現(xiàn),這個(gè)方法在內(nèi)部總共會(huì)經(jīng)過三個(gè)步驟:
    1.首先會(huì)判斷該視圖是否能響應(yīng)觸摸事件,如果不能響應(yīng),返回nil,表示該視圖不響應(yīng)此觸摸事件。
    2.調(diào)用pointInside:withEvent:(該方法用來判斷點(diǎn)擊事件發(fā)生的位置是否處于當(dāng)前視圖范圍內(nèi))。如果pointInside:withEvent:返回NO,那么hiteTest:withEvent:也直接返回nil。
    3.如果pointInside:withEvent:返回YES,則向當(dāng)前視圖的所有子視圖發(fā)送hitTest:withEvent:消息,所有子視圖的遍歷順序是從最頂層視圖一直到到最底層視圖,即從subviews數(shù)組的末尾向前遍歷。(這個(gè)遍歷的過程可理解為從外到里)直到有子視圖返回非空對(duì)象或者全部子視圖遍歷完畢;
    若第一次有子視圖返回非空對(duì)象,則 hitTest:withEvent:方法返回此對(duì)象,該對(duì)象再繼續(xù)1,2,3的步驟;
    若所有子視圖都返回非,則hitTest:withEvent:方法返回該視圖自身,說明事件傳遞到此結(jié)束,已經(jīng)找到了最合適的視圖來處理觸摸事件。

三、響應(yīng)者鏈

響應(yīng)者:繼承UIResponder的對(duì)象稱之為響應(yīng)者對(duì)象,能夠處理touchesBegan等觸摸事件。
響應(yīng)者鏈:由很多響應(yīng)者鏈接在一起組合起來的一個(gè)鏈條稱之為響應(yīng)者鏈條

每個(gè)能執(zhí)行hitTest:方法的view都屬于事件傳遞的一部分,但是,只有pointInside返回YES的view才屬于響應(yīng)者鏈條

通過事件傳遞找到最合適的處理觸摸事件的view后,它就是第一響應(yīng)者。所以事件傳遞是自下而上,而響應(yīng)者鏈?zhǔn)亲陨隙碌摹#╳indow上最外面的那個(gè)view稱為上)

四、實(shí)際應(yīng)用

1、擴(kuò)大響應(yīng)范圍;
2、根據(jù)響應(yīng)者鏈找到當(dāng)前的controller;
3、截獲事件,讓需要的view去響應(yīng)這個(gè)事件;
等等。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 用戶以多種方式操縱他們的iOS設(shè)備,例如觸摸屏幕或搖動(dòng)設(shè)備。 iOS會(huì)解釋用戶何時(shí)以及如何操作硬件并將此信息傳遞到...
    坤坤同學(xué)閱讀 4,036評(píng)論 7 19
  • 1、響應(yīng)鏈的傳遞 Responder一點(diǎn)也不神秘————iOS用戶響應(yīng)者鏈完全剖析(建議全看)看完上面一篇應(yīng)該能完...
    RasonWu閱讀 10,416評(píng)論 3 36
  • 前言: 在咱們平時(shí)的開發(fā)過程中,每天都在敲著帶有各種響應(yīng)事件的代碼,那咱們iOS的響應(yīng)事件是怎樣傳遞的呢?系統(tǒng)是怎...
    圣僧留步閱讀 382評(píng)論 0 0
  • iOS中加載的時(shí)候會(huì)先執(zhí)行main函數(shù) int main(int argc, charchar * argv[])...
    Ven415閱讀 293評(píng)論 0 0
  • 久違的晴天,家長會(huì)。 家長大會(huì)開好到教室時(shí),離放學(xué)已經(jīng)沒多少時(shí)間了。班主任說已經(jīng)安排了三個(gè)家長分享經(jīng)驗(yàn)。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,557評(píng)論 16 22