iOS事件響應鏈及hit-test原理總結

響應者對象(UIResponder)

在iOS中不是任何對象都能處理事件,只有繼承了UIResponder的對象才能接受并處理事件,我們稱之為“響應者對象”。以下都是繼承自UIResponder的,所以都能接收并處理事件。

  • UIApplication
  • UIViewController
  • UIView
    那么為什么繼承自UIResponder的類就能夠接收并處理事件呢?

因為UIResponder中提供了以下4個對象方法來處理觸摸事件。
UIResponder內部提供了以下方法來處理事件觸摸事件:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
加速計事件
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;
遠程控制事件
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;

iOS 事件響應鏈全過程分兩步:

一.事件的傳遞:從用戶觸摸位置找到最上層view,這個過程是從底層向上層尋找的過程。

iOS使用hit-testing尋找觸摸的view。
Hit-Testing 叫做命中測試。
Hit-Testing通過檢查觸摸點是否在關聯(lián)的view邊界內,如果在,則遞歸地檢查該view的所有子view。
在層級上處于lowest(就是離用戶最近的view)且邊界范圍包含觸摸點的view成為hit-test view。確定hit-test view后,它傳遞觸摸事件給該view。

下面是官方的小例子:

hit-test過程
  1. 觸摸點在view A中,所以要先檢查子view B和C。
  2. 觸摸點不在view B中,但在C中,所以檢查C的子view D和E。
  3. 觸摸點不在D中,但在E中。View E是這個層級上處于lowest的- view的邊界范圍包含觸摸點,所以它成為了hit-test view。

Hit-test view是處理觸摸事件的第一選擇,如果hit-test view不能處理事件,該事件將從事件響應鏈中尋找響應器,直到系統(tǒng)找到一個處理事件的對象。若不能處理,則就有事件傳遞鏈了,繼續(xù)看下面的事件傳遞鏈。

Hit-Test命中測試方法判斷一個view能否作為Responder還有3個條件:

  1. 透明度<0.01
  2. hidden=YES的時候
  3. userInteractionEnabled = NO

以上這3個情況,該view(以及該view所有的子視圖) 命中測試方法會忽略掉,也就不會有事件響應了。

二.事件響應:從上層沿著響應鏈傳到底層,和第一步剛好是相反的。

響應者對象:能處理事件的對象,也就是繼承自UIResponder的對象
作用:能很清楚的看見每個響應者之間的聯(lián)系,并且可以讓一個事件多個對象處理。

如何判斷上一個響應者
1> 如果當前這個view是控制器的view,那么控制器就是上一個響應者
2> 如果當前這個view不是控制器的view,那么父控件就是上一個響應者

下面是參考官方的響應流程圖:

事件傳遞過程
左半圖:

initial view若不能處理事件,則傳到其父視圖view
view若不能處理,則傳到其父視圖,因為它還不是最上層視圖
這里view的父視圖是view controller的view,因為這個view也不能處理事件,因此傳給view controller
若view controller也不能處理此事件,則傳到window
若window也不能處理此事件,則傳到app單例對象Application
若UIApplication單例對象也不能處理,則表示無效事件
右半圖:

initial view一直傳遞直到最上層view(原話:A view passes an event up its view controller’s view hierarchy until it reaches the topmost view.)
topmost view傳遞事件到它所在的控制器(原話:The topmost view passes the event to its view controller.)
view controller傳遞事件到topmost view的父視圖,重復前三步,走到到達root controller(原話:passes the event to its topmost view’s superview. Steps 1-3 repeat until the event reaches the root view controller.)
由root控制器傳遞事件到window(原話:The root view controller passes the event to the window object.)
若window也不能處理此事件,則傳到app單例對象Application
若UIApplication單例對象也不能處理,則表示無效事件

事件處理的整個流程總結:

  1. 觸摸屏幕產生觸摸事件后,觸摸事件會被添加到由UIApplication管理的事件隊列中(即,首先接收到事件的是UIApplication)。
  2. UIApplication會從事件隊列中取出最前面的事件,把事件傳遞給應用程序的主窗口(keyWindow)。
  3. 主窗口會在視圖層次結構中找到一個最合適的視圖來處理觸摸事件。(至此,第一步已完成)
  4. 最合適的view會調用自己的touches方法處理事件
  5. touches默認做法是把事件順著響應者鏈條向上拋。

如何做到一個事件多個對象處理:
因為系統(tǒng)默認做法是把事件上拋給父控件,所以可以通過重寫自己的touches方法和父控件的touches方法來達到一個事件多個對象處理的目的。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ 
// 1.自己先處理事件...
NSLog(@"do somthing...");
// 2.再調用系統(tǒng)的默認做法,再把事件交給上一個響應者處理
[super touchesBegan:touches withEvent:event]; 
}

事件的傳遞和響應的區(qū)別:
事件的傳遞是從上到下(父控件到子控件),事件的響應是從下到上(順著響應者鏈條向上傳遞:子控件到父控件。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 在iOS開發(fā)中經常會涉及到觸摸事件。本想自己總結一下,但是遇到了這篇文章,感覺總結的已經很到位,特此轉載。作者:L...
    WQ_UESTC閱讀 6,237評論 4 26
  • 前言: 按照時間順序,事件的生命周期是這樣的: 事件的產生和傳遞(事件如何從父控件傳遞到子控件并尋找到最合適的vi...
    reviewThis閱讀 803評論 1 2
  • 觸摸事件的生命周期 當我們手指觸碰屏幕的那一刻,一個觸摸事件便產生了。經過進程間通信,觸摸事件被傳遞到合適的應用之...
    Gintok閱讀 1,516評論 0 3
  • 本文主要講解iOS觸摸事件的一系列機制,涉及的問題大致包括: 觸摸事件由觸屏生成后如何傳遞到當前應用? 應用接收觸...
    baihualinxin閱讀 1,266評論 0 9
  • 上一章 追尋影蹤目錄 冬日雪,忌外出。通往天香城的官道每隔一個時辰就會清掃一次,及近年關,南來北往的車輛絡繹不絕...
    ARUNANHUI閱讀 191評論 0 0

友情鏈接更多精彩內容