响应链

响应链:顾名思义,是一个链条,响应传递的链条。

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

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

你可能感兴趣的:(响应链)