美文网首页
事件的传递和响应

事件的传递和响应

作者: MrQun | 来源:发表于2022-02-13 19:19 被阅读0次

    响应链

    image.png
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        self.window.rootViewController = [[ViewController alloc] init];
        [self.window makeKeyAndVisible];
        return YES;
    }
     
    - (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:animated];
        UIView *view = [[UIView alloc] init];
        [self.view addSubview:view];
        
        UILabel *label = [[UILabel alloc] init];
        [view addSubview:label];
        [self logOutResponderChain:label];
    }
    
    - (void)logOutResponderChain:(UIResponder *)responder {
        UIResponder *nextResponder = responder.nextResponder;
        NSLog(@"%@ -> ", NSStringFromClass([responder class]));
        while (nextResponder) {
            NSLog(@"%@ -> ", NSStringFromClass([nextResponder class]));
            nextResponder = nextResponder.nextResponder;
        }
        NSLog(@"*");
    }
    // - 打印结果 : UILabel -> UIView -> UIView -> ViewController -> UIDropShadowView -> UITransitionView -> UIWindow -> UIWindowScene -> UIApplication -> AppDelegate -> *
    
    1. 能响应事件的 必须是UIResponser的子类;
    2. 响应链是 子视图-> 父视图的.

    传递链

    image.png
    1. 首先判断主窗口(keyWindow)自己是否能接受触摸事件
    2. 判断触摸点是否在自己身上
    3. 子控件数组中从后往前遍历子控件,重复前面的两个步骤(所谓从后往前遍历子控件,就是首先查找子控件数组中最后一个元素(后添加到view上的子view - > 先添加到view上的子view),然后执行1、2步骤)
    4. view,比如叫做fitView,那么会把这个事件交给这个fitView,再遍历这个fitView的子控件,直至没有更合适的view为止。
    5. 如果没有符合条件的子控件,那么就认为自己最合适处理这个事件,也就是自己是最合适的view。
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        NSLog(@"AView --- hitTest");
        UIView * view = [super hitTest:point withEvent:event];
        NSLog(@"AView --- hitTest --- return %@", view.class);
        return view;
    }
    
    - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
        NSLog(@"AView --- pointInside");
        return [super pointInside:point withEvent:event];
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        NSLog(@"AView --- touchesBegan");
    }
    // - [vc.view addSubView: AView]; [AView addSubView: BView]; [BView addSubView: CView];
    

    // - 触摸CView
    AView --- hitTest
    AView --- pointInside --- Yes
    BView --- hitTest
    BView --- pointInside --- Yes
    CView --- hitTest
    CView --- pointInside --- Yes
    CView --- hitTest --- return CView
    BView --- hitTest --- return CView
    AView --- hitTest --- return CView
    CView --- touchesBegan

    // - 触摸BView但是不触摸CView
    AView --- hitTest
    AView --- pointInside --- Yes
    BView --- hitTest
    BView --- pointInside --- Yes
    CView --- hitTest
    CView --- pointInside --- No
    CView --- hitTest --- return (null)
    BView --- hitTest --- return BView
    AView --- hitTest --- return BView
    BView --- touchesBegan

    总结

    用户产生触摸事件 -> 事件进入UIApplication事件队列 -> UIApplication分发事件给keyWindow -> [UIWindow hitTest:withEvent:] -> [UIView hitTest:withEvent:] -> … -> [UIView hitTest:withEvent:] -> 返回最合适的view给keyWindow -> [UIWindow _sendTouchesForEvent:] -> [UIView touchesBegan:withEvent:]。

    相关文章

      网友评论

          本文标题:事件的传递和响应

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