(一)、响应者对象—— UIResponder
在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接受并处理事件,我们称之为“响应者对象”。以下都是继承自UIResponder的,所以都能接收并处理事件。
@interface UIApplication : UIResponder
@interface UIViewController : UIResponder
@interface UIView : UIResponder
那么为什么继承自UIResponder的类就能够接收并处理事件呢?
因为UIResponder中提供了以下4个对象方法来处理触摸事件
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
(二)、事件的传递
- 点击一个UIView或产生一个触摸事件A,这个触摸事件A会被添加到由UIApplication管理的事件队列中(即,首先接收到事件的是UIApplication)。
- UIApplication会从事件对列中取出最前面的事件A(队列按照先进先出的原则),把事件A传递给应用程序的主窗口(keyWindow)。
- 窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件。
![](https://img.haomeiwen.com/i2050812/6b9276890a54b124.png)
注*:UIView不能接收触摸事件的三种情况:
不允许交互:userInteractionEnabled = NO(UIImageView默认不能接受触摸事件,即userInteractionEnabled = NO)
隐藏:如果把父控件隐藏,那么子控件也会隐藏,隐藏的控件不能接受事件
透明度:如果设置一个控件的透明度<0.01,会直接影响子控件的透明度。alpha:0.0~0.01为透明。
如何寻找最合适的view的底层原理
- 事件传递给一个控件,不管这个控件能不能处理事件,也不管触摸点在不在这个控件上,事件都会先传递给这个控件;
- 这个控件就会调用他自己的hitTest:withEvent:方法,
- hit:withEvent:方法底层会调用pointInside:withEvent:方法
- pointInside:withEvent:方法判断点在不在方法调用者的坐标系上。
- 如果返回YES,代表点在方法调用者的坐标系上;返回NO代表点不在方法调用者的坐标系上。
(三)、事件的响应
响应者链的事件传递过程:
- 如果当前view是控制器的view,那么控制器就是上一个响应者,事件就传递给控制器;如果当前view不是控制器的view,那么父视图就是当前view的上一个响应者,事件就传递给它的父视图
- 在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理
- 如果window对象也不处理,则其将事件或消息传递给UIApplication对象
- 如果UIApplication也不能处理该事件或消息,则将其丢弃
![](https://img.haomeiwen.com/i2050812/ff28167c659fc415.png)
(四)、触摸事件的传递和响应整体过程
- 用户点击屏幕后产生的一个触摸事件,经过一系列的传递过程后,会找到最合适的视图控件来处理这个事件;
- 找到最合适的视图控件后,就会调用控件的touches方法来作具体的事件处理touchesBegan、touchesMoved、touchedEnded…
- 这些touches方法的默认做法是将事件顺着响应者链条向上传递,将事件交给上一个响应者进行处理。
参考文章:
史上最详细的iOS之事件的传递和响应机制-原理篇
网友评论