事件传递响应总结

事件的产生和传递

  1. 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中;
  2. UIApplication 会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口keyWindow;
  3. 主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件,这也是整个事件处理过程的第一步;
  4. 找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理。

UIView不接收触摸事件的三种情况

  1. 不接收用户交互 userInteractionEnabled = NO
  2. 隐藏 hidden = YES
  3. 透明 alpha = 0.0 ~ 0.01

提示: UIImageView 的 userInteractionEnabled默认就是NO,因此 UIImageView 以及它的子控件默认是不能接收触摸事件的。

view中跟事件传递相关的三个方法

// 什么时候调用:当事件传递给当前view时,会调用当前view的hitTest方法。
// 作用:寻找最适合的view
// 返回值:返回谁,谁就是最适合的view,谁就响应事件,就会调用谁的touches方法

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    // 1. 判断自己能否接收事件
    // 2. 点在不在自己身上
    // 3. 从后往前遍历自己的子控件,把事件传递给子控件,调用子控件的hitTest,
   // 4. 如果子控件没有找到最适合的view,那么自己就是最适合的view。
    return [super hitTest:point withEvent: event];
}

// 作用:点在不在自己身上,调用当前view一个方法(pointInside:)
// 什么时候调用:在hitTest内部调用的
// 返回值:YES 在当前view身上,NO 不在
// point: 当前触摸点
// 注意:必须得要跟方法调用者在同一个坐标系
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
      return YES;
}
// touchesBegan 方法的默认做法是将事件顺着响应者链条向上传递,将事件交给上一个响应者进行处理
// 就会调用上一个响应者的touches方法
// 上一个响应者是谁?先看当前view是否为控制器的view,如果是,那么上一个响应者就是他所在的控制器,如果不是,上一个响应者就是他的父控件。
// 千辛万苦找到你这个view,但是如果没有处理,那么就按照默认来
- (void)touchesBegin:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"%@----touch", [self class]);
}

自己实现hitTest:withEvent:方法

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    // 1. 判断自己能否接收事件
    if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) {
        // 不能接收事件
       return nil;
    }

    // 2. 点在不在自己身上
    if (![self pointInside:point withEvent: event]) {
        return nil;
    }

    // 3. 从后往前遍历自己的子控件,把事件传递给子控件,调用子控件的hitTest
    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;
        }
    }
    // 4. 如果子控件没有找到最适合的view,那么自己就是最适合的view
    return self;
}

传递和响应是两个过程

完整过程如下

  1. 先将事件对象由上往下传递(由父控件传递给子控件),找到最合适的控件来处理这个事件;
  2. 调用最合适控件的touches...方法;
  3. 如果调用了[super touches...];就会将事件顺着响应者链条往上传递,传递给上一个响应者;
  4. 接着就会调用上一个响应者的touches...方法

如何判断上一个响应者

  1. 如果当前这个view是控制器的view,那么控制器就是上一个响应者;
  2. 如果当前这个view不是控制器的view,那么父控件就是上一个响应者。

备注

视频链接-第五章上
参考文章,也是看过那个视频写出来的

你可能感兴趣的:(事件传递响应总结)