Understanding Event Handling,Responders,and the Responder Chain

了解事件的传递以及如何管理它们

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用响应者对象接收和处理事件,响应者对象是UIResponder是任一实例,常用的子类包括UIView、UIViewController、UIApplication等。响应者对象接收最初的事件数据,首先去处理该事件,如果不能处理,就必须将之传递到下一个响应者对象那里。当app收到一个事件时,UIKit会自动地将这一事件分发给最适合的响应者对象那里,这个对象就成为第一响应者。没有被处理的事件会沿着活动的响应者链一个个对象进行传递,响应者链是app中响应者对象形成的一种动态结构。app中不存在单独的响应者链

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定义了对象在响应者之间传递的规则,但你可以通过重写响应者对象合适的属性来改变这些规则。图1展示了默认情况下的响应者链,当前界面包含了一个label、一个textfield、一个按钮和两个背景view。如果textfield没有处理事件,UIKit 会把事件传递给textfield的父view对象,然后是window的根view。从根view开始,响应者链将事件转发给view所在的viewController,然后才会转给window。如果window也不能处理该事件,UIKit会将事件分发给UIApplication对象,或者给不在该响应者链中的其他UIResponder实例的代理进行处理(??)


Figure1.png
寻找第一响应者

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.

每种类型的事件,UIKit都会指派一个第一响应者并且优先将事件转发给它。第一响应者根据事件类型不同而不同
触摸事件:触摸所在的view
按压事件:获得焦点的view
摇动事件:开发者或UIKit指定的对象
远程控制事件:开发者或UIKit指定的对象
编辑菜单消息:开发者或UIKit指定的对象

注意:运动事件(motion events) 与加速计、陀螺仪和磁强计有关,该类事件不遵循响应链。相反,核心运动(Core Motion)会将这些事件直接传递给您指定的对象。具体可参考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 like cut(_:) 、copy(_:), or paste(_:).

控件使用动作消息直接与和他们绑定的目标对象通信。当用户与控件交互时,控件会调用目标对象的action方法,换句话说,它会发送动作消息给目标对象。动作消息不是事件,但它们同样会利用响应者链。当一个控件的目标对象是nil时,UIKit会从目标对象开始沿着响应链寻找,直到找到了实现了action方法的对象。例如,UIKit编辑菜单使用该特性来寻找实现了cut(_:) 、copy(_:), or paste(_:)方法的响应者对象。

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.

如果一个view已经被添加了手势识别器,那么手势识别器会在view之前优先接收到触摸或按压事件。如果该view的全部手势识别器都不能识别手势,事件才会被传递到view进行处理。如果view也不能处理,UIKite会将事件沿着响应链传递。
(所以,手势的优先级高于响应链哦)

确定哪个响应者包含触摸事件

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方式来确定事件在哪里发生的。具体来说,UIKit将触摸位置与view对象进行逐级对比。UIView的hitTest(_:with:)方法逐级执行,去寻找最深一级的包含特定触摸的子view。这个view就成了该触摸事件的第一响应者。
注意:如果一个事件的位置在view的bounds之外,hitTest(_:with:)方法就会忽略该view及其所有subview。因此,当一个view的clipsToBounds属性是false的时候,在该view之外的subview是不会被hitTest(_:with:)返回的,即便事件的位置在该subview的界限之内

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固定地将每个触摸分配给包含该触摸的view。当触摸事件发生时,UIKit会为每个事件创建UITouch对象,这个UITouch对象只会在触摸结束时才释放。当触摸的位置或其他属性变化时,UIKit会将新信息更新到该UITouch对象中。唯一不会改变的属性是其所属的view。即便触摸的位置移出原来的view,该触摸的view属性也不会改变

改变响应者链

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.
  1. If the view controller’s view is the root view of a window, the next responder is the window object.
  2. 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.

你可以通过重写响应者对象的next属性来改变响应者链。当你这么做的时候,下一个响应对象就是你重写next属性return的那个
许多UIKit class 已经重写了该属性且返回了特定的对象

  • UIView对象,如果该view是viewController的root view,那么下一个响应者就是viewController;否则,下一个响应者就是它的superview。
  • UIViewController对象
    • 如果该viewController的view是一个window的root view,那么它的下一个响应者就是window
    • 如果该viewController是被其他viewController所present出来的,那它的下一个响应者就是present它的那个viewController
  • UIWindow对象,window的下一个响应者是UIApplication对象
  • UIApplication对象,它的下一个响应者对象是app delegate。不过app delegate不能是UIResponder的实例,不能是view、viewController或者app对象自己
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 一. Hit-Testing 什么是Hit-Testing?对于触摸事件, window首先会尝试将事件交给事件触...
    面糊阅读 814评论 0 50
  • Understanding Event Handling, Responders, and the Respond...
    frankisbaby阅读 397评论 0 0
  • 在开发过程中,大家或多或少的都会碰到令人头疼的手势冲突问题,正好前两天碰到一个类似的bug,于是借着这个机会了解了...
    闫仕伟阅读 5,294评论 2 23
  • 好奇触摸事件是如何从屏幕转移到APP内的?困惑于Cell怎么突然不能点击了?纠结于如何实现这个奇葩响应需求?亦或是...
    Lotheve阅读 56,585评论 51 597
  • 在iOS开发中经常会涉及到触摸事件。本想自己总结一下,但是遇到了这篇文章,感觉总结的已经很到位,特此转载。作者:L...
    WQ_UESTC阅读 5,987评论 4 26