响应链

作者: 韩大锤 | 来源:发表于2018-09-14 16:54 被阅读0次
    响应链:顾名思义,是一个链条,响应传递的链条。

    当我们在屏幕上点击了一个地方发生了什么?

    A.用户点击屏幕,系统的RunLoop会检查到一个触摸的输入源
    B.触摸的输入源会被系统封装成UIEvent对象传递给Appdelegate
    C.Appdelegate向UIApplication传递事件,然后UIApplication向UIWindow传递事件
    D.UIWindow会向Controller的View传递事件
    E.View收到父响应者传递的事件后,递归调用- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event方法找到最合适的视图
    F.如果能响应,执行它的代码 ,不能的话,递归到上一个响应者,执行响应
    如果一直递归到appdelegate到都没有响应,则这次点击就被丢掉

    举个栗子:


    image.png

    我们有四个VIew,分别为ViewA,ViewB, ViewC, ViewD.
    我们在ViewA里头重写

    • (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    • (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event
      两个方法
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        NSLog(@"hitTest进入A_View");
        UIView * view = [super hitTest:point withEvent:event];
        NSLog(@"hitTest离开A_View");
        return view;
    }
    
    - (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event {
        NSLog(@"pointInsideA_view");
        BOOL isInside = [super pointInside:point withEvent:event];
        NSLog(@"pointInsideA_view  isInside:%d",isInside);
        return isInside;
    }
    
    

    我们在ViewB里头重写

    • (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    • (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event
      两个方法
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        NSLog(@"hitTest进入B_View");
        UIView * view = [super hitTest:point withEvent:event];
        NSLog(@"hitTest离开B_View");
        return view;
    }
    
    - (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event {
        NSLog(@"pointInsideB_view");
        BOOL isInside = [super pointInside:point withEvent:event];
        NSLog(@"pointInsideB_view isInside:%d", isInside);
        return isInside;
    }
    

    我们在ViewC里头重写

    • (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    • (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event
      两个方法
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        NSLog(@"hitTest进入C_View");
        UIView * view = [super hitTest:point withEvent:event];
        NSLog(@"hitTest离开C_View");
        return view;
    }
    
    - (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event {
        NSLog(@"pointInsideC_view");
        BOOL isInside = [super pointInside:point withEvent:event];
        NSLog(@"pointInsideC_view isInside:%d", isInside);
        return isInside;
    }
    

    我们在ViewD里头重写

    • (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    • (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event
      两个方法
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        NSLog(@"hitTest进入D_View");
        UIView * view = [super hitTest:point withEvent:event];
        NSLog(@"hitTest离开D_View");
        return view;
    }
    
    - (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event {
        NSLog(@"pointInsideD_view");
        BOOL isInside = [super pointInside:point withEvent:event];
        NSLog(@"pointInsideD_view isInside:%d",isInside);
        return isInside;
    }
    

    我们点击VIewD,会得到如下Log信息


    image.png

    事件传递链:
    ViewA--->ViewB--->ViewC--->ViewD
    我们可以看到,找到了ViewD为最佳响应视觉

    我们点击ViewB,会得到如下Log信息


    image.png

    事件传递链:
    ViewA--->ViewB--->ViewC
    我们可以看到,当找到ViewC的时候,ViewC没有在点击的区域,所以ViewB就是最佳的响应视觉

    Demo链接:https://github.com/DuffYang/PerfectResponse

    相关文章

      网友评论

          本文标题:响应链

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