响应链
顾名思义,响应链就是对某些行为的响应,按照一定的机制进行流动,所形成的链条
在iOS
中:用户点击屏幕时,会触发以下流程:
-
捕获事件:手机系统捕获到
单击
行为,也称为单击
事件 -
封装事件:把包含该事件的信息封装成
UITouch
和UIEvent
对象 - 查找程序:找到可以处理该事件的运行程序
-
查找第一响应者:利用
hitTest:(CGPoint)point
方法,在视图层级中,从下往上逐级查找可以响应该事件的响应者,将最后的响应者作为第一响应者 -
事件转发:如果第一响应者不处理该事件,再用
nextResponder
方法,从上往下,逐级转发,直到没有响应者响应。
image如下图所示:用户点击输入框时,
UITextField
就成为第一响应者,如果它不处理该点击事件,就转发该事件给它的superView
,如果有视图控制器,就转给视图控制器,接着再到UIWindow
,再到UIApplication
,最终到AppDelegate
,如果AppDelegate
也不处理,该事件就被丢弃
这个过程就是事件的响应链。
这里提到几个概念:事件、响应者、第一响应者,下面分别进行介绍:
事件
用户跟
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
网友评论