目录:
1.事件分类
2.响应者链(Responder Chain)
3.事件分发(Event Delivery)数组
内容:
1.事件分类:
- 触控事件(Touch Event)(单点、多点触控以及各类手势操做)
- 传感器事件(Motion Event)(重力、加速度传感器等)
- 远程控制事件(Remote-Control Event)(远程遥控iOS设备多媒体播放等)
2.响应者链(Responder Chain)
UIResponder是全部响应对象的基类,在UIResponder类中定义了处理上述各类事件的接口。咱们熟悉的UIApplication、 UIViewController、UIWindow和全部继承自UIView的UIKit类都直接或间接的继承自UIResponder,因此它们的实例都是能够构成响应者链的响应者对象。ide
响应者链就是由一系列的响应者对象构成的一个层次结构。对象

- 响应者链一般是由视图(UIView)构成的;
- 一个视图的下一个响应者是它视图控制器(UIViewController)(若是有的话),而后再转给它的父视图(Super View);
- 视图控制器(若是有的话)的下一个响应者为其管理的视图的父视图;
- 单例的窗口(UIWindow)的内容视图将指向窗口自己做为它的下一个响应者
- 单例的应用(UIApplication)是一个响应者链的终点,它的下一个响应者指向nil,以结束整个循环。
3.事件分发(Event Delivery)
3.1 第一响应者(First responder)
指的是当前接受触摸的响应者对象(一般是一个UIView对象),即表示当前该对象正在与用户交互,它是响应者链的开端。继承
整个响应者链和事件分发的使命都是找出第一响应者。接口
咱们能够控制一个View让其成为First Responder,经过实现 canBecomeFirstResponder方法并返回YES可使当前View成为第一响应者,或者调用View的becomeFirstResponder方法也能够,例如当UITextField调用该方法时会弹出键盘进行输入,此时输入框控件就是第一响应者。队列
3.2 hit-test view
hit-test view(将触摸事件传递给其处理的视图)过程:事件
- iOS系统检测到手指触摸(Touch)操做时会将其打包成一个UIEvent对象,并放入当前活动Application的事件队列,
- 单例的UIApplication会从事件队列中取出触摸事件并传递给单例的UIWindow来处理,
- UIWindow对象首先会使用hitTest:withEvent:方法寻找这次Touch操做初始点所在的视图(View),即须要将触摸事件传递给其处理的视图
- hitTest:withEvent:,方法会在其视图层级结构中的每一个视图上调用pointInside:withEvent
- pointInside:withEvent:方法判断触摸点是否在当前视图内
- 若返回NO,则hitTest:withEvent:返回nil;
- 若返回YES,则向当前视图的全部子视图(subviews)发送hitTest:withEvent:消息
- 全部子视图的遍历顺序是从最顶层视图一直到到最底层视图,即从subviews数组的末尾向前遍历,直到有子视图返回非空对象或者所有子视图遍历完毕;
- 如全部子视图都返回非,则hitTest:withEvent:方法返回自身(self)。
- 若第一次有子视图返回非空对象,则hitTest:withEvent:方法返回此对象,处理结束;
至此,本次点击事件的第一响应者就经过响应者链的事件分发逻辑成功的找到了。ip
NOTE:it
若是最终hit-test没有找到第一响应者,或者第一响应者没有处理该事件,则该事件会沿着响应者链向上回溯,若是UIWindow实例和UIApplication实例都不能处理该事件,则该事件会被丢弃;io
- hitTest:withEvent:方法将会忽略一些视图:
- 隐藏(hidden=YES)的视图,
- 禁止用户操做(userInteractionEnabled=YES)的视图,
- 以及alpha级别小于0.01(alpha<0.01)的视图。
- 若是一个子视图的区域超过父视图的bound区域(父视图的clipsToBounds 属性为NO,这样超过父视图bound区域的子视图内容也会显示),那么正常状况下对子视图在父视图以外区域的触摸操做不会被识别,由于父视图的pointInside:withEvent:方法会返回NO,这样就不会继续向下遍历子视图了。