事件传递链和响应者链总结
之前也学习过这个内容这次在复习的时候,就想着写一下总结:
初始事件传递链和响应者链
1. 事件传递链:
事件传递链:
将用户在应用程序中的进行交互的事件发送到视图层次中的适当对象。在这个事件的传递过程中,从根视图开始查找,并递归向下查找最合适的处理该事件的视图(第一响应者)。
传递流程:
- 事件产生: 用户通过与设备交互生成事件,系统将事件传递给引用的
UIApplication
实例,以开始事件分发。 UIApplication
事件分发:UIApplication
实例将事件传递给当前的UIWindow
对象,进一步查找适合的响应者。UIWindow
事件分发:当前UIWindow
通过调用hitTest:withEvent:
方法来遍历整个视图层次结构,找到合适的视图来响应工作。- 命中测试(
hitTest:withEvent:
)
**hitTest:withEvent:
是寻找第一响应者的核心方法。**它通过以下步骤工作:- 检查当前视图的属性隐藏
hidden = NO
,交互userInteractionEnabled=YES
、透明度alpha>0.01
三者都满足才能拥有响应的能力。 - 调用
pointInside:withEvent:
,确定触摸点是否在当前视图的边界范围内。 - 从后往前遍历子视图,递归调用子视图的
hitTest:withEvent:
方法。 - 直到找到合适的子视图,返回子视图作为第一响应者,否则返回当前视图本身。
- 检查当前视图的属性隐藏
- 第一响应者确定 :如果确定了当前触摸点在当前视图上,同时当前视图没有任何子视图,那么当前视图就成为第一响应者并开始处理触摸事件。
相应的大致流程过程:UIKit
--> active app's event queue
--> window
--> root view
--> ...... --> lowest view
事件传递的本质就是为了让我们找到第一响应者。
总结第一响应者:
- 能够响应触摸事件
- 触摸点在自己的边界范围内
- 没有任何子视图或者所有子视图都不在触摸点上。
2. 响应者链
响应者链
在事件传递链中找到了第一响应者,但是第一响应者不一定可以响应事件,因为他可能没有实现触摸事件。
传递流程
对于响应者链的传递流程可以通过下面这张图来看:
左边的app响应者链:
- 初始视图对象尝试对事件进行处理,如果无法处理,就将事件传递给父视图对象。在视图树,初始视图并不是最顶端的视图。
- 父视图也会进行同样的尝试,因为相同的原因,只能将事件继续向上传递。
- 视图控制器中最顶层的视图也进行相同的尝试,结果处理不了就会传递给视图控制器。
- 视图控制器也一样无法处理,于是继续向上传递给主窗体对象(
window
)。 - 主窗体也无法处理,就会继续传给app的单例实体对象。
- 最后单例实体对象没有处理,就会将事件丢弃掉。
右边的app响应者链:
- 视图将事件沿着视图控制器的视图树向上传递,直到最顶端的视图。
- 顶端的视图无法处理就直接交给视图控制器。
- 视图控制器无法处理就将事件传递给其顶端视图所在的父视图,重复1~3,知道到达最顶端的跟视图控制器。
- 跟视图控制器将事件传递给主窗体对象。
- 主窗体对象传递给app的单例实体对象。
总结响应者链流程
判断当前视图能否响应,再去判断当前视图的nextResponder
,如果是VC
的View
,那么nextResponer
就是VC
。
如果不是控制器的View
,上一个响应者就是SuperView
。
相应的大致流程过程:第一响应者->super view->......->ViewController->window->application
总结:
- 触摸事件发生之后,系统会生成简单的
UIEvent
。 - 将
UIEvent
产生的事件添加到UIApplication
队列中。 - 然后
UIApplication
将事件分发给UIWindow
,主窗口会在视图层次中找到合适的视图处理触摸事件。 - 不但递归调用
hitTest
方法来确定第一响应者。 - 如果第一响应者无法响应事件,就按照响应者链往上传递,传递给父视图。
- 一直传到
UIApplication
,如果都没有响应则事件丢弃。