iOS事件響應(yīng)鏈及hit-test原理總結(jié)

響應(yīng)者對(duì)象(UIResponder)

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

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

因?yàn)閁IResponder中提供了以下4個(gè)對(duì)象方法來處理觸摸事件。
UIResponder內(nèi)部提供了以下方法來處理事件觸摸事件:

- (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;
加速計(jì)事件
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;
遠(yuǎn)程控制事件
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;

iOS 事件響應(yīng)鏈全過程分兩步:

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

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

下面是官方的小例子:

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

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

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

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

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

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

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

如何判斷上一個(gè)響應(yīng)者
1> 如果當(dāng)前這個(gè)view是控制器的view,那么控制器就是上一個(gè)響應(yīng)者
2> 如果當(dāng)前這個(gè)view不是控制器的view,那么父控件就是上一個(gè)響應(yīng)者

下面是參考官方的響應(yīng)流程圖:

事件傳遞過程
左半圖:

initial view若不能處理事件,則傳到其父視圖view
view若不能處理,則傳到其父視圖,因?yàn)樗€不是最上層視圖
這里view的父視圖是view controller的view,因?yàn)檫@個(gè)view也不能處理事件,因此傳給view controller
若view controller也不能處理此事件,則傳到window
若window也不能處理此事件,則傳到app單例對(duì)象Application
若UIApplication單例對(duì)象也不能處理,則表示無效事件
右半圖:

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的父視圖,重復(fù)前三步,走到到達(dá)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單例對(duì)象Application
若UIApplication單例對(duì)象也不能處理,則表示無效事件

事件處理的整個(gè)流程總結(jié):

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

如何做到一個(gè)事件多個(gè)對(duì)象處理:
因?yàn)橄到y(tǒng)默認(rèn)做法是把事件上拋給父控件,所以可以通過重寫自己的touches方法和父控件的touches方法來達(dá)到一個(gè)事件多個(gè)對(duì)象處理的目的。

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

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

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

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容