美文网首页
iOS事件传递响应总结

iOS事件传递响应总结

作者: _老妖怪 | 来源:发表于2021-05-07 15:53 被阅读0次

    事件的产生和传递

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

    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<UITouch *> *)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,那么父控件就是上一个响应者。

    转载自作者:黑化肥发灰
    链接:https://www.jianshu.com/p/8d60b3943f08

    相关文章

      网友评论

          本文标题:iOS事件传递响应总结

          本文链接:https://www.haomeiwen.com/subject/xewlhhtx.html