了解事件的傳遞以及如何管理它們
Apps receive and handle events using responder objects. A responder object is any instance of the UIResponder class, and common subclasses include UIView , UIViewController、UIApplication.Responders receive the raw event data and must either handle the event or forward it to another responder object. When your app receives an event, UIKit automatically directs that event to the most appropriate responder object, known as the first responder. Unhandled events are passed from responder to responder in the active responder chain, which is a dynamic configuration of your app’s responder objects. There is no single responder chain within your app.
app用響應(yīng)者對(duì)象接收和處理事件,響應(yīng)者對(duì)象是UIResponder是任一實(shí)例吨瞎,常用的子類(lèi)包括UIView、UIViewController、UIApplication等送矩。響應(yīng)者對(duì)象接收最初的事件數(shù)據(jù)赶撰,首先去處理該事件,如果不能處理糊啡,就必須將之傳遞到下一個(gè)響應(yīng)者對(duì)象那里拄查。當(dāng)app收到一個(gè)事件時(shí),UIKit會(huì)自動(dòng)地將這一事件分發(fā)給最適合的響應(yīng)者對(duì)象那里棚蓄,這個(gè)對(duì)象就成為第一響應(yīng)者堕扶。沒(méi)有被處理的事件會(huì)沿著活動(dòng)的響應(yīng)者鏈一個(gè)個(gè)對(duì)象進(jìn)行傳遞,響應(yīng)者鏈?zhǔn)莂pp中響應(yīng)者對(duì)象形成的一種動(dòng)態(tài)結(jié)構(gòu)梭依。app中不存在單獨(dú)的響應(yīng)者鏈
UIKit defines default rules for how objects are passed from one responder to the next, but you can always change those rules by overriding the appropriate properties in your responder objects. Figure 1 shows the default responder chains in an app whose interface contains a label, a text field, a button, and two background views. If the text field does not handle an event, UIKit sends the event to the text field’s parent UIView object, followed by the root view of the window. From the root view, the responder chain diverts to the owning view controller before directing the event to the window. If the window does not handle the event, UIKit delivers the event to the UIApplication object, and possibly to the app delegate if that object is an instance of UIResponder and not already part of the responder chain.
UIKit定義了對(duì)象在響應(yīng)者之間傳遞的規(guī)則稍算,但你可以通過(guò)重寫(xiě)響應(yīng)者對(duì)象合適的屬性來(lái)改變這些規(guī)則。圖1展示了默認(rèn)情況下的響應(yīng)者鏈役拴,當(dāng)前界面包含了一個(gè)label糊探、一個(gè)textfield、一個(gè)按鈕和兩個(gè)背景view河闰。如果textfield沒(méi)有處理事件科平,UIKit 會(huì)把事件傳遞給textfield的父view對(duì)象,然后是window的根view姜性。從根view開(kāi)始瞪慧,響應(yīng)者鏈將事件轉(zhuǎn)發(fā)給view所在的viewController,然后才會(huì)轉(zhuǎn)給window部念。如果window也不能處理該事件弃酌,UIKit會(huì)將事件分發(fā)給UIApplication對(duì)象氨菇,或者給不在該響應(yīng)者鏈中的其他UIResponder實(shí)例的代理進(jìn)行處理(?矢腻?)
尋找第一響應(yīng)者
For every type of event, UIKit designates a first responder and sends the event to that object first. The first responder varies based on the type of event.
Touch events
The first responder is the view in which the touch occurred.
Press events
The first responder is the responder that has focus.
Shake-motion events
The first responder is the object that you (or UIKit) designate as the first responder.
Remote-control events
The first responder is the object that you (or UIKit) designate as the first responder.
Editing menu messages
The first responder is the object that you (or UIKit) designate as the first responder.
每種類(lèi)型的事件门驾,UIKit都會(huì)指派一個(gè)第一響應(yīng)者并且優(yōu)先將事件轉(zhuǎn)發(fā)給它。第一響應(yīng)者根據(jù)事件類(lèi)型不同而不同
觸摸事件:觸摸所在的view
按壓事件:獲得焦點(diǎn)的view
搖動(dòng)事件:開(kāi)發(fā)者或UIKit指定的對(duì)象
遠(yuǎn)程控制事件:開(kāi)發(fā)者或UIKit指定的對(duì)象
編輯菜單消息:開(kāi)發(fā)者或UIKit指定的對(duì)象
注意:運(yùn)動(dòng)事件(motion events) 與加速計(jì)多柑、陀螺儀和磁強(qiáng)計(jì)有關(guān)奶是,該類(lèi)事件不遵循響應(yīng)鏈。相反竣灌,核心運(yùn)動(dòng)(Core Motion)會(huì)將這些事件直接傳遞給您指定的對(duì)象聂沙。具體可參考Core Motion Framework
控件接收到事件之后的處理
Controls communicate directly with their associated target object using action messages. When the user interacts with a control, the control calls the action method of its target object—in other words, it sends an action message to its target object. Action messages are not events, but they may still take advantage of the responder chain. When the target object of a control is
nil
, UIKit starts from the target object and walks the responder chain until it finds an object that implements the appropriate action method. For example, the UIKit editing menu uses this behavior to search for responder objects that implement methods with names likecut(_:) 、copy(_:), or paste(_:)
.
控件使用動(dòng)作消息直接與和他們綁定的目標(biāo)對(duì)象通信初嘹。當(dāng)用戶(hù)與控件交互時(shí)及汉,控件會(huì)調(diào)用目標(biāo)對(duì)象的action方法,換句話(huà)說(shuō)屯烦,它會(huì)發(fā)送動(dòng)作消息給目標(biāo)對(duì)象坷随。動(dòng)作消息不是事件,但它們同樣會(huì)利用響應(yīng)者鏈驻龟。當(dāng)一個(gè)控件的目標(biāo)對(duì)象是nil時(shí)温眉,UIKit會(huì)從目標(biāo)對(duì)象開(kāi)始沿著響應(yīng)鏈尋找,直到找到了實(shí)現(xiàn)了action方法的對(duì)象翁狐。例如类溢,UIKit編輯菜單使用該特性來(lái)尋找實(shí)現(xiàn)了cut(_:) 、copy(_:), or paste(_:)
方法的響應(yīng)者對(duì)象露懒。
If a view has an attached gesture recognizer, the gesture recognizer receives touch and press events before the view receives them. If all of the view’s gesture recognizers fail to recognize their gestures, the events are passed to the view for handling. If the view does not handle them, UIKit passes the events up the responder chain.
如果一個(gè)view已經(jīng)被添加了手勢(shì)識(shí)別器闯冷,那么手勢(shì)識(shí)別器會(huì)在view之前優(yōu)先接收到觸摸或按壓事件。如果該view的全部手勢(shì)識(shí)別器都不能識(shí)別手勢(shì)懈词,事件才會(huì)被傳遞到view進(jìn)行處理蛇耀。如果view也不能處理,UIKite會(huì)將事件沿著響應(yīng)鏈傳遞坎弯。
(所以蒂窒,手勢(shì)的優(yōu)先級(jí)高于響應(yīng)鏈哦)
確定哪個(gè)響應(yīng)者包含觸摸事件
UIKit uses view-based hit-testing to determine where touch events occur. Specifically, UIKit compares the touch location to the bounds of view objects in the view hierarchy. The
hitTest(_:with:)
method of UIView walks the view hierarchy, looking for the deepest subview that contains the specified touch. That view becomes the first responder for the touch event.
UIKit使用基于view的hittest方式來(lái)確定事件在哪里發(fā)生的。具體來(lái)說(shuō)荞怒,UIKit將觸摸位置與view對(duì)象進(jìn)行逐級(jí)對(duì)比。UIView的hitTest(_:with:)
方法逐級(jí)執(zhí)行秧秉,去尋找最深一級(jí)的包含特定觸摸的子view褐桌。這個(gè)view就成了該觸摸事件的第一響應(yīng)者。
注意:如果一個(gè)事件的位置在view的bounds之外象迎,hitTest(_:with:)
方法就會(huì)忽略該view及其所有subview荧嵌。因此呛踊,當(dāng)一個(gè)view的clipsToBounds
屬性是false的時(shí)候,在該view之外的subview是不會(huì)被hitTest(_:with:)
返回的啦撮,即便事件的位置在該subview的界限之內(nèi)
UIKit permanently assigns each touch to the view that contains it. UIKit creates each [
UITouch
] object when the touch first occurs, and it releases that touch object only after the touch ends. As the touch location or other parameters change, UIKit updates the [UITouch
] object with the new information. The only property that does not change is the containing view. Even when the touch location moves outside the original view, the value in the touch’s [view
] property does not change.
UIKit固定地將每個(gè)觸摸分配給包含該觸摸的view谭网。當(dāng)觸摸事件發(fā)生時(shí),UIKit會(huì)為每個(gè)事件創(chuàng)建UITouch對(duì)象赃春,這個(gè)UITouch對(duì)象只會(huì)在觸摸結(jié)束時(shí)才釋放愉择。當(dāng)觸摸的位置或其他屬性變化時(shí),UIKit會(huì)將新信息更新到該UITouch對(duì)象中织中。唯一不會(huì)改變的屬性是其所屬的view锥涕。即便觸摸的位置移出原來(lái)的view,該觸摸的view屬性也不會(huì)改變狭吼。
改變響應(yīng)者鏈
You can alter the responder chain by overriding the [
next
] property of your responder objects. When you do this, the next responder is the object that you return.
Many UIKit classes already override this property and return specific objects.
- [
UIView
] is the root view of a view controller, the next responder is the view controller; otherwise, the next responder is the view’s superview.- [
UIViewController
] objects.
- If the view controller’s view is the root view of a window, the next responder is the window object.
- If the view controller was presented by another view controller, the next responder is the presenting view controller.
- [
UIWindow
] objects. The window's next responder is the [UIApplication
] object.- [
UIApplication
] object. The next responder is the app delegate, but only if the app delegate is an instance of [UIResponder
] and is not a view, view controller, or the app object itself.
你可以通過(guò)重寫(xiě)響應(yīng)者對(duì)象的next
屬性來(lái)改變響應(yīng)者鏈层坠。當(dāng)你這么做的時(shí)候,下一個(gè)響應(yīng)對(duì)象就是你重寫(xiě)next
屬性return的那個(gè)
許多UIKit class 已經(jīng)重寫(xiě)了該屬性且返回了特定的對(duì)象
- UIView對(duì)象刁笙,如果該view是viewController的root view破花,那么下一個(gè)響應(yīng)者就是viewController;否則疲吸,下一個(gè)響應(yīng)者就是它的superview座每。
- UIViewController對(duì)象
- 如果該viewController的view是一個(gè)window的root view,那么它的下一個(gè)響應(yīng)者就是window
- 如果該viewController是被其他viewController所present出來(lái)的磅氨,那它的下一個(gè)響應(yīng)者就是present它的那個(gè)viewController
- UIWindow對(duì)象尺栖,window的下一個(gè)響應(yīng)者是UIApplication對(duì)象
- UIApplication對(duì)象,它的下一個(gè)響應(yīng)者對(duì)象是app delegate烦租。不過(guò)app delegate不能是UIResponder的實(shí)例延赌,不能是view、viewController或者app對(duì)象自己