iOS 事件傳遞機(jī)制

事件傳遞機(jī)制

  1. 響應(yīng)者鏈的事件傳遞過程:

    1. 如果當(dāng)前view是控制器的view,那么控制器就是上一個(gè)響應(yīng)者,事件就傳遞給控制器;如果當(dāng)前view不是控制器的view,那么父視圖就是當(dāng)前view的上一個(gè)響應(yīng)者,事件就傳遞給它的父視圖。
    2. 在視圖層次結(jié)構(gòu)的最頂級(jí)視圖,如果也不能處理收到的事件或消息,則其將事件或消息傳遞給window對(duì)象進(jìn)行處理。
    3. 如果window對(duì)象也不處理,則其將事件或消息傳遞給UIApplication對(duì)象。
    4. 如果UIApplication也不能處理該事件或消息,則將其丟棄。
  2. 事件處理的整個(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)者鏈條向上拋。
  3. 事件的傳遞與響應(yīng):

    1. 當(dāng)一個(gè)事件發(fā)生后,事件會(huì)從父控件傳給子控件,也就是說由UIApplication -> UIWindow -> UIView -> initial view,以上就是事件的傳遞,也就是尋找最合適的view的過程。
    2. 接下來是事件的響應(yīng)。首先看initial view能否處理這個(gè)事件,如果不能則會(huì)將事件傳遞給其上級(jí)視圖(inital view的superView);如果上級(jí)視圖仍然無法處理則會(huì)繼續(xù)往上傳遞;一直傳遞到視圖控制器view controller,首先判斷視圖控制器的根視圖view是否能處理此事件;如果不能則接著判斷該視圖控制器能否處理此事件,如果還是不能則繼續(xù)向上傳 遞;(對(duì)于第二個(gè)圖視圖控制器本身還在另一個(gè)視圖控制器中,則繼續(xù)交給父視圖控制器的根視圖,如果根視圖不能處理則交給父視圖控制器處理);一直到 window,如果window還是不能處理此事件則繼續(xù)交給application處理,如果最后application還是不能處理此事件則將其丟棄。
    3. 在事件的響應(yīng)中,如果某個(gè)控件實(shí)現(xiàn)了touches...方法,則這個(gè)事件將由該控件來接受,如果調(diào)用了[supertouches….];就會(huì)將事件順著響應(yīng)者鏈條往上傳遞,傳遞給上一個(gè)響應(yīng)者;接著就會(huì)調(diào)用上一個(gè)響應(yīng)者的touches….方法。
PS:事件的傳遞和響應(yīng)的區(qū)別:

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

PPS:如何做到一個(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)用如何找到最合適的控件來處理事件?

  1. 首先判斷主窗口(keyWindow)自己是否能接受觸摸事件

  2. 判斷觸摸點(diǎn)是否在自己身上

  3. 子控件數(shù)組中從后往前遍歷子控件,重復(fù)前面的兩個(gè)步驟(所謂從后往前遍歷子控件,就是首先查找子控件數(shù)組中最后一個(gè)元素,然后執(zhí)行1、2步驟)

  4. view,比如叫做fitView,那么會(huì)把這個(gè)事件交給這個(gè)fitView,再遍歷這個(gè)fitView的子控件,直至沒有更合適的view為止。

  5. 如果沒有符合條件的子控件,那么就認(rèn)為自己最合適處理這個(gè)事件,也就是自己是最合適的view。

尋找最合適控件的底層實(shí)現(xiàn)

  1. 注意點(diǎn):hitTest方法內(nèi)部會(huì)調(diào)用pointInside方法,詢問觸摸點(diǎn)是否在自己身上,當(dāng)遍歷子控件時(shí),傳入的坐標(biāo)點(diǎn)要進(jìn)行轉(zhuǎn)化,將父視圖上的坐標(biāo)點(diǎn)轉(zhuǎn)換到所要傳遞的子視圖上的坐標(biāo)點(diǎn)

  2. hitTest的底層實(shí)現(xiàn):當(dāng)控件接收到觸摸事件的時(shí)候,不管能不能處理事件,都會(huì)調(diào)用hitTest方法,此方法的底層實(shí)現(xiàn)是:1:先看自己是否能接受觸摸事件 2:再看觸摸點(diǎn)是否在自己身上 3:從后往前遍歷子控件,拿到子控件后,再次重復(fù)1,2步驟,要把父控件上的坐標(biāo)點(diǎn)轉(zhuǎn)換為子控件坐標(biāo)系下的點(diǎn),再次執(zhí)行hitTest方法。

  3. 若是最后還沒有找到合適的view,那么就return self,自己就是合適的view

參考文章: http://www.itdecent.cn/p/2e074db792ba

最后編輯于
?著作權(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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