事件的传递
- 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中。
- UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keywWndow)。
- 主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件,这也是整个事件处理过程的第一步。
- 找到合适的视图控制控件后,就会调用视图控件的touches方法来做具体的事件处理。
- 触摸事件的传递是从父控件传到子控件UIApplication –>UIWindow ->父控件->子控件
- 注意点:如果父控件不能接收触摸事件,那么自控件就不可能接收到触摸事件UIView不接收触摸事件的三种情况
- 不接收用户交互
- self.view.userInteractionEnabled = NO;
- 隐藏
- self.view.hidden = YES;
- 透明
- self.view.alpha = 0;
// point:是方法调用者坐标系上的触摸点的位置 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { // 1.判断下能否接收触摸事件 if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.0) return nil; // 2.判断下点在不在控件上 if ([self pointInside:point withEvent:event] == NO) return nil; // 3.从后往前遍历子控件 int count = (int)self.subviews.count; for (int i = count - 1; i >= 0 ; i--) { // 取出显示在最前面的子控件 UIView *childView = self.subviews[i]; // 转换成子控件坐标系上点 CGPoint childP = [self convertPoint:point toView:childView]; UIView *fitView = [childView hitTest:childP withEvent:event]; if (fitView) { return fitView; } } // 表示没有比自己更合适的view return self; }
如何找到最合适的view
- 自己是否能接收触摸事件
- 触摸点是否在自己的身上
- 从后往前遍历子控件,重复前面的两个步骤
- 如果没有符合条件的子控件,那么就自己最适合处理
响应者链条
- 定义:是由多个响应者对象连接起来的链条。
- 作用:能很清楚的看见每个响应者之间的联系,并且可以让一个事件多个对象处理。
- 响应者对象:能处理事件的对象。
- 默认做法是将事件顺着响应者链条向上传递,将事件交给上一个响应者进行处理。
- 如何判断上一个响应者
- 如果当前这个view是控制器的view,那么控制器就是上一个响应者。
- 如果当前这个view不是控制器的view,那么父控件就是上一个响应者。
//寻找合适的view //什么时候调用,只要一个事件传递给一个控件,就会调用这个控件的hitTest,返回谁,谁就是最合适的view //point:表示方法调用者坐标系上的点。 - (UIView* )hitTest:(CGPoint)point withEvent:(UIEvent *)event{ return self; } //判断下当前这个点在不在方法调用者上 //使用注意点:点必须是方法调用者上的坐标系,才会判断准确 -(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{ //返回YES事件才会往子控件传递, return YES; }