跟著官方文檔從0到1學(xué)習(xí)iOS中的響應(yīng)鏈

First Steps

Tips1:Understanding Event Handling, Responders, and the Responder Chain

  • 概述:Apps 接受和響應(yīng)事件均使用 UIResponder 對(duì)象,它的子類包括 UIView, UIViewController, UIApplication 。一個(gè) responder 類接受原生的事件數(shù)據(jù)然后將它傳遞給其他的 responder 對(duì)象。當(dāng)你的 app 接受到了一個(gè)事件, UIKit 將會(huì)自動(dòng)的將這個(gè)事件發(fā)送給最可能接受的對(duì)象 —— first responder 。它沒(méi)有能 handle 的事件將會(huì)通過(guò)響應(yīng)鏈傳遞給一個(gè)又一個(gè)的 responder,這些都是在你的 app 中動(dòng)態(tài)配置的。在你的 app 中,不止有一條響應(yīng)鏈。 UIKit 默認(rèn)定義了對(duì)象如何在 responder 之間傳遞的規(guī)則,不過(guò)你可以通過(guò)自己修改某些方法的方式來(lái)完成對(duì)這一特性的修改,定制自己的傳遞規(guī)則。當(dāng)界面上有一個(gè) textfield 兩個(gè)背景 view 時(shí),首先如果這個(gè) textfield 無(wú)法 handle 某一事件,它將會(huì)被傳遞給它的父視圖上去。在 rootView 上,它將會(huì)把這個(gè)事件傳遞給它自己的 viewController, 然后才會(huì)繼續(xù)傳遞給 UIWindow。如果 UIWindow 還無(wú)法 handle 這個(gè)事件,它將會(huì)被傳遞給 UIApplication 對(duì)象,當(dāng)這個(gè)對(duì)象時(shí) UIResponder 的實(shí)例并且也不在響應(yīng)鏈中,這個(gè)事件也有可能會(huì)被傳遞給 UIApplicationDelegate 。
    responderChain.png
  • 為一個(gè)事件選擇第一響應(yīng)者:對(duì)于每一種事件來(lái)說(shuō), UIKit 都會(huì)先選擇某一種 firstResponder 然后先把事件傳遞給它。
    • Touch event:它的第一響應(yīng)者是當(dāng) touch 動(dòng)作發(fā)生時(shí)所在的 view
    • Press event:它的第一響應(yīng)者是
    • Shake-motion event/RemoteControl event/EdtingMenu event:它的第一響應(yīng)者是你指定的 firstResponder
    • 需要注意的是:motion 事件和螺旋器,加速儀等有關(guān)系,它并不 follow 響應(yīng)鏈。
    • 控件類直接與他們的 target object 使用 action messages 發(fā)送消息。也就是說(shuō),當(dāng)一個(gè)用戶與一個(gè) UIControl 類進(jìn)行交互時(shí),它將把這個(gè)動(dòng)作消息發(fā)送給它的目標(biāo)對(duì)象。實(shí)際上 UIControl 類也能享受到響應(yīng)鏈的優(yōu)點(diǎn),因?yàn)楫?dāng)一個(gè)控件并沒(méi)有設(shè)置它的 target action 時(shí), UIKit 會(huì)開(kāi)始沿著當(dāng)前 UIControl 對(duì)象的響應(yīng)鏈尋找一個(gè)可能接受這個(gè) action method 的對(duì)象。例如: UIKit 的 edting menu 就是用這個(gè)特性去尋找可以實(shí)現(xiàn) cut,copy 等方法的對(duì)象。
    • 如果一個(gè) view 添加了一個(gè)手勢(shì),這個(gè)手勢(shì)會(huì)首先接受 touch 和 press 事件,只有當(dāng)所有的手勢(shì)都無(wú)法接受這個(gè)事件后,這個(gè)事件才會(huì)被傳遞給這個(gè) view 去 handle。
  • 決定哪一個(gè)響應(yīng)者包含一個(gè) Touch 事件:UIKit 使用 hitTest:withEvent: 方法去判斷當(dāng)前 touch 事件是在哪里發(fā)生的。 UIKit 會(huì)在繼承鏈中比較這個(gè) touch location 和 view 對(duì)象的 bounds。 hitTest:withEvent: 方法會(huì)穿越 UIView 的 view 繼承鏈,然后尋找最底下包含這個(gè) touch 事件的子視圖,這個(gè) view 就會(huì)成為這個(gè) touch 事件的 firstResponder
    • 如果一個(gè) touch 事件的位置在 view 的 bounds 外,hitTest:withEvent: 方法就會(huì)忽略這個(gè) view 和它的所有子視圖。當(dāng)一個(gè) view 的 clipToBounds 屬性設(shè)置為 NO 時(shí),表示并不裁剪這個(gè) view 的子視圖。那么如果這個(gè) view 的 subViews 如果在這個(gè) view 的 bounds 外,即使這個(gè) subView 接收到了 touch 事件,也不會(huì)去處理的。也就是說(shuō),hitTest:withEvent: 方法已經(jīng)自動(dòng)把這個(gè) subView 過(guò)濾掉了。
    • 當(dāng)?shù)谝淮伟l(fā)生了這個(gè) touch 事件時(shí), UIKit 會(huì)創(chuàng)建 UITouch 對(duì)象,然后只有等到這個(gè) touch 事件結(jié)束時(shí)才會(huì)釋放這個(gè) touch 對(duì)象。當(dāng) touch 的 location 或者其他的參數(shù)改變時(shí), UIKit 會(huì)自動(dòng)的更新 UITouch 對(duì)象的信息。唯一不會(huì)改變的屬性為這個(gè) touch 事件的 containing view。即使這個(gè) touch 事件的位置有可能會(huì)移出它一開(kāi)始的 origin containing view 的范圍,這個(gè) touch view 的屬性也不會(huì)改變。
  • 改變響應(yīng)鏈:你可以通過(guò)重寫(xiě) nextResponder 屬性來(lái)改變響應(yīng)鏈。當(dāng)你這樣做時(shí), nextResponder 對(duì)象就是你返回的對(duì)象。許多 UIKit 類已經(jīng)改寫(xiě)了這個(gè)屬性
    • UIView 對(duì)象:如果這個(gè) view 是一個(gè) viewController 的 rootView,那么它的 nextResponder 就是這個(gè) viewController,否則,這個(gè) view 的 nextResponder 是它的 superView
    • UIViewController 對(duì)象:如果這個(gè) viewController 是被另外一個(gè) viewController present 過(guò)來(lái)的,那么他的 nextResponder 就是 present 它的那個(gè) viewController
    • UIWindow 對(duì)象:它的 nextResponder為 UIApplication 對(duì)象
    • UIApplication 對(duì)象:只有當(dāng)一個(gè) app delegate 對(duì)象是 UIResponder,并且它不是一個(gè) view,viewController或者 app 自身時(shí),UIApplication對(duì)象的 nextResponder 才為 app delegate 對(duì)象

Tips2:class UIResponder

  • 概述:responder 對(duì)象是 UIResponder 類的實(shí)例,他們?cè)谝粋€(gè) UIKit app 中組成了事件處理的支柱。很多 key object 也是 responder 對(duì)象。包括 UIApplication 對(duì)象, UIViewCOntroller 對(duì)象,和 UIView 對(duì)象(包括 UIWindow 對(duì)象)。當(dāng)事件發(fā)生時(shí),UIKit 將這些事件分發(fā)給你的 app 內(nèi)的 responder 對(duì)象來(lái)處理。
  • 事件有許多種類,包括 touch 事件,motion 事件,remote-control 事件,和 press 事件。想要去 handle 這些事件對(duì)象,我們必須重寫(xiě)相應(yīng)的方法,比如說(shuō)我們?nèi)绻?handle 一個(gè) touch 事件,我們可以實(shí)現(xiàn) touchesBegan:withEvent:, touchesMoved:withEvent:, touchesEnded:withEvent:, 和touchesCancelled:withEvent: 方法。在 touch 的條件下,responder 對(duì)象使用這些 UIKit 提供的事件信息去追蹤 touches 的改變,并且也可以更新 app 的界面。
  • Responder 對(duì)象處理 UIEvent 對(duì)象,也可以接受其他通過(guò) inputView 輸入的普通 input,系統(tǒng)的 keyboard 是一個(gè)最明顯的 inputView。當(dāng) user 點(diǎn)擊 textfield 和 textView 對(duì)象時(shí),那個(gè) view 就會(huì)成為 firstResponder 然后被展示在屏幕上。同理,你也可以創(chuàng)建自己的 custom input view 然后將它展示在屏幕上。如果想將一個(gè)普通的 input view 關(guān)聯(lián)為一個(gè) responder ,可以將那個(gè) view 通過(guò)設(shè)置為 inputView 屬性分配給 responder。

Tips3:class UIEvent

  • 概述:Apps 可以接受很多類型的事件,包括 touch 事件, motion 事件,和 press 事件等。Touch 事件是最常見(jiàn)的事件,它會(huì)傳遞給 touch 最初發(fā)生的 view。 RemoteControl 事件使 responder 對(duì)象能夠接收一個(gè)從外部控制的事件,例如耳機(jī),所以它可以控制音頻和視頻。
  • 一個(gè) touch event 對(duì)象包括很多 touches (即有很多手指同時(shí) touch)所以和 event 有一定的關(guān)系。一個(gè) touch event 對(duì)象可能包括一個(gè)或多個(gè) touches ,每個(gè) touch 都是一個(gè) UITouch 對(duì)象。當(dāng) touch event 發(fā)生時(shí),系統(tǒng)自動(dòng)的將它路由到適當(dāng)?shù)?responder,然后調(diào)用適當(dāng)?shù)姆椒ā@?touchesBegan:withEvent:。然后 responder 接著使用這些 touches 去定義可能發(fā)生的動(dòng)作
  • 在一個(gè)多點(diǎn)觸控過(guò)程做,UIKit 會(huì)復(fù)用同樣的 UIEvent 對(duì)象,所以你永遠(yuǎn)都不應(yīng)該去保存一個(gè) event 對(duì)象/一個(gè)對(duì)象從 event 返回。如果你需要保存一個(gè) responder 以外的數(shù)據(jù),你應(yīng)該去保存數(shù)據(jù),將 UITouch / UIEvent 對(duì)象的數(shù)據(jù)保存到本地?cái)?shù)據(jù)結(jié)構(gòu)中。

總結(jié):

  • 此為 iOS 開(kāi)發(fā)中的 UIKit 響應(yīng)鏈部分的第一部分,翻譯 + 個(gè)人理解自蘋(píng)果官方文檔 Touches, Presses, and Gestures,如有理解錯(cuò)誤望海涵和指正。
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 一. Hit-Testing 什么是Hit-Testing?對(duì)于觸摸事件, window首先會(huì)嘗試將事件交給事件觸...
    面糊閱讀 1,048評(píng)論 0 50
  • 好奇觸摸事件是如何從屏幕轉(zhuǎn)移到APP內(nèi)的?困惑于Cell怎么突然不能點(diǎn)擊了?糾結(jié)于如何實(shí)現(xiàn)這個(gè)奇葩響應(yīng)需求?亦或是...
    Lotheve閱讀 59,621評(píng)論 51 604
  • 在iOS開(kāi)發(fā)中經(jīng)常會(huì)涉及到觸摸事件。本想自己總結(jié)一下,但是遇到了這篇文章,感覺(jué)總結(jié)的已經(jīng)很到位,特此轉(zhuǎn)載。作者:L...
    WQ_UESTC閱讀 6,251評(píng)論 4 26
  • 用戶以多種方式操縱他們的iOS設(shè)備,例如觸摸屏幕或搖動(dòng)設(shè)備。 iOS會(huì)解釋用戶何時(shí)以及如何操作硬件并將此信息傳遞到...
    坤坤同學(xué)閱讀 4,128評(píng)論 7 19
  • “吃飯啦”! 過(guò)了兩分鐘,熊爸總是第一個(gè)過(guò)來(lái)的,順便把熊兒子抱過(guò)來(lái),照舊費(fèi)幾番口舌,半哄半塞把熊弄進(jìn)兒童椅。 咪姐...
    澤微閱讀 727評(píng)論 8 8

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