响应链
顾名思义,响应链就是对某些行为的响应,按照一定的机制进行流动,所形成的链条
在iOS中:用户点击屏幕时,会触发以下流程:
-
捕获事件:手机系统捕获到
单击行为,也称为单击事件 -
封装事件:把包含该事件的信息封装成
UITouch和UIEvent对象 - 查找程序:找到可以处理该事件的运行程序
-
查找第一响应者:利用
hitTest:(CGPoint)point方法,在视图层级中,从下往上逐级查找可以响应该事件的响应者,将最后的响应者作为第一响应者 -
事件转发:如果第一响应者不处理该事件,再用
nextResponder方法,从上往下,逐级转发,直到没有响应者响应。
如下图所示:用户点击输入框时,
UITextField就成为第一响应者,如果它不处理该点击事件,就转发该事件给它的superView,如果有视图控制器,就转给视图控制器,接着再到UIWindow,再到UIApplication,最终到AppDelegate,如果AppDelegate也不处理,该事件就被丢弃
image
这个过程就是事件的响应链。
这里提到几个概念:事件、响应者、第一响应者,下面分别进行介绍:
事件
用户跟
iOS设备的交互行为就称为事件
在iOS中,有4种事件类型:
- 点击事件:在屏幕上的点击
-
移动事件:指的是设备的移动,如摇晃,与
Core Motion的移动不同 - 远程控制事件:指的是从耳际或其它附件上接收到的指令,大多用来控制多媒体,如调整音量,切换歌曲等
- 按压事件:指设备上的物理按钮按压操作
响应者
响应者是用于响应和处理事件的抽象接口
在iOS中,响应者都是UIResponder类的实例,它是事件处理的核心对象,包括常用的UIView、UIWindow、UIApplication、UIViewController等
第一响应者
当
App接收到事件时,UIKit框架会自动将该事件派给最合适的响应者,这个响应者就是第一响应者
决定谁是第一响应者
在iOS中,第一响应者取决于事件类型
-
点击事件:第一响应者是事件发生所在的
view - 按压事件:第一响应者是获取焦点的响应者
- 移动事件:第一响应者由开发者指定
- 远程控制事件:第一响应者由开发者指定
- 编辑菜单消息:第一响应者由开发者指定
注意:关于加速计、陀螺仪、磁力计等的移动事件,不遵循响应链规则,由Core Motion框架处理
然而,当事件发生时,第一响应者并不总是来立即处理该事件,当对象是Control,或者该对象有Gesture recognizer时,会进行额外的处理。
-
Control:
Controls与关联的target目标对象,是通过action消息机制进行通信的。当用户与control交互时,control会先调用target的action方法。如果control的target为空,UIKit就会按照响应链来处理该事件。 -
Gesture recognizer:如果一个
view添加有手势识别器,会先用手势识别器来处理事件,如果所有的手势识别器都不能处理事件,才会传给view处理,之后遵循响应链。
决定哪个响应者来接收触摸事件
UIKit是通过视图层的hit-testing方法来决定,触摸事件发生的位置。
UIKit会调用方法hitTest方法,由下往上,逐一遍历视图层,通过pointInside方法将触摸点所在的位置坐标与视图进行比较,最终查到的最顶层的view就是接收该事件的第一响应者
注意:如果触摸点在视图区域的外边,该视图及所在的子视图分支整个都将被忽略。比如:一个view的 clipsToBounds属性为NO,subview就可以有部分显示在该view的外面,对外面这部分的触摸事件,在执行``pointInside方法与view比较时会返回NO,结果导致该view`及子视图分支被忽略
一旦触摸事件发生,UIKit就会给包含该触摸点的view分配一个touch对象,该对象在整个触摸周期中,位置和内部参数可能会发生变化,但它的view属性,永远不变,哪怕触摸点已经离开了view的视图范围
改变响应链
可以通过重写
nextResponder方法,来选择下一个响应者
许多UIKit类都通过重写该方法,来返回指定的对象
-
UIView:如果是
viewController的根视图,next responder就是viewController,否则就是superView -
UIViewController:如果是
window的根视图控制器,next responder就是window;如果是由另一个视图控制器模态出来的,next responder就是该视图控制器 -
UIWindow:
next responder是UIApplication对象 -
UIApplication:如果
AppDelegate是UIResponder的对象,且不是view、view controller、application,那么next responder就是AppDelegate














网友评论