触摸事件的产生、传递与响应
在iOS系统中,发生触摸事件以后,系统会把该事件加入到一个由UIApplication管理的事件队列中。
- 事件的分发:UIApplication会从事件队列中取出最前面的事件,并将事件分发下去处理,一般先把事件发送给应用程序的主窗口(keyWindow)
- 主窗口会在视图层次结构中,通过hitTest方法寻找最合适的视图View来处理触摸事件,事件处理的第一步
- 找到合适的视图View控件之后,就会调用该控件的touches方法来处理相应的事件
- touchesBegan……
- touchesMoved……
- touchesEnded……
事件的传递:触摸事件的传递是从父控件传递到子控件的,以下图为例,事件的传递过程如下:
- 点击绿色:
- UIApplication ->UIWindow ->白色 ->绿色
- 点击蓝色
- UIApplication ->UIWindow ->白色 ->橙色->蓝色
- 点击来黄色
- UIApplication ->UIWindow ->白色 ->橙色->蓝色->黄色
注意:如果父控件不能接收触摸事件,那么子控件就不可能接收到触摸事件
- 不能接收触摸事件的三种情况:
- 没有开启用户交互:userInteractionEnabled = NO
- 控件隐藏:hidden = YES
- 透明度太低:alpha = 0.0~0.01
如何找到最合适的控件来处理事件:
- 判断自己能否接收触摸事件
- 触摸点是否在自己身上
- 按照添加子控件的顺序从后往前遍历子控件,重复上面的两步
- 如果没有符合条件的子控件,那就默认自己是最合适处理事件的控件
- 寻找最合适控件的底层实现
寻找最合适控件代码的底层实现:
1 //触摸事件发生时寻找最合适的View,系统调用 hitTest: withEvent:方法找到最合适的View 2 //当前View发生触摸事件就会调用该方法 3 // hitTest: withEvent:方法的底层实现 4 - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ 5 //判断触摸点是否在当前的View上,如果不在直接返回空 6 if (![self pointInside:point withEvent:event]) { 7 return nil; 8 } 9 //判断当前View是否能接收事件,不能接收事件的三种情况 10 if (self.userInteractionEnabled == NO || self.alpha <= 0.01 || self.hidden == YES) { 11 return nil; 12 } 13 //从后往前遍历子控件查找最合适的View 14 int count = (int) self.subviews.count; 15 for (int i = count -1; i >= 0; i--) { 16 //取出父控件View上的子控件 17 UIView *childV = self.subviews[i]; 18 //将父控件View上的点坐标进行转换 19 CGPoint chP = [self convertPoint:point toView:childV]; 20 //子控件再去查找最优View 21 UIView *fitV = [childV hitTest:chP withEvent:event]; 22 //如果子控件找到就返回最合适的View 23 if (fitV) { 24 return fitV; 25 } 26 } 27 //循环结束都没找到就返回当前View作为最合适的View 28 return self; 29 }
事件处理的过程:
- 事件产生并进行传递之后,找到最合适的控件处理事件
- 找到最合适的视图控件之后,就会调用该控件的touches方法处理具体的事件
- 默认情况下,touches方法调用[super touches……]方法,将事件顺着响应者链条向上传递,将事件交给上一个响应者进行处理,即调用touches……方法
事件响应者链条示意图:
- 响应者链条:由多个响应者对象连接起来的链条
- 作用:能清楚的看见每个响应者之间的联系,并且可以让一个事件被多个对象处理
- 响应者对象:能处理事件的对象
上一个响应者的判断:
- 如果当前的控件view是控制器的view,那么控制器就是上一个响应者
- 如果当前这个控件view不是控制器的view,那么它的父控件就是上一个响应者
响应者链条的事件传递处理:
- 如果上一个view的控制器存在,就传递给控制器;如果控制器不存在,则将其传递给父控件
- 在视图层次结构的最顶级视图,如果也不能处理接收到的事件或消息,则将其传递给Window对象进行处理
- 如果window对象不能处理,则将事件或消息传递给UIApplication对象
- 如果UIApplication也不能处理,则将事件或消息丢弃

浙公网安备 33010602011771号