响应者链

什么是响应者链

在iOS的事件传递过程中需要通过多个响应者来寻找最合适的事件接收者,把这个过程中的响应者串联起来就是响应者链。

事件的产生和传递过程

当系统检测到触摸事件event发生的时候,将event放入当前活动的UIApplication事件队列中,UIApplication会从队列中取出event传递给主窗口UIWindow(keyWindow)keyWindow会通过递归找到合适的View,调用touches;

触摸事件event——>UIApplication队列——>UIWindow对列接收——>keyWindow递归找到View——>View调用合适的touches——>处理事件

递归寻找响应者 (hitTest:withEvent:和pointInside:withEvent:)
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    NSLog(@"%@-hit-%@", NSStringFromClass(self.class), event);
    // 1.判断能否接受点击事件
    if (!self.userInteractionEnabled || self.alpha == 0.0 || self.hidden) {
        return nil;
    }
    // 2.判断点是否点击在当前视图上
    if (![self pointInside:point withEvent:event]) {
        return nil;
    }
    // 反向遍历子视图
    __block UIView *fitView = nil;
    [self.subviews.reverseObjectEnumerator.allObjects enumerateObjectsUsingBlock:^(UIView *childView, NSUInteger idx, BOOL * _Nonnull stop) {
        // 把当前坐标系上的点转换成子控件上的点
        CGPoint chidlPoint = [self convertPoint:point toView:childView];
        // 判断这个点上是否在子视图上,找到第一个响应视图
        fitView = [childView hitTest:chidlPoint withEvent:event];
        if (fitView) {
            *stop = YES;
        }
    }];
    if (fitView) {
        return fitView;
    }
    return self;
}
寻找合适的响应者

如果响应者处理不了touches事件,会将事件上移,该类的上一级如果是UIView,子视图处理事件,处理不了,寻找它的父视图
该类的上一级如果是UIViewController,则是由它所属的控制器处理
事件上移到最顶层如果处理不了,把事件传递给UIWindowUIWindow处理不了给UIApplicationUIApplication默认不响应,这个touches就会被吃掉

寻找当前view的UIViewController

思路:
根据响应者链寻找,找到相应当前view事件的控制器
1.给当前控制器添加一个导航条 ‘nav’ 是window的rootViewController

UIViewController *vc = ((AppDelegate *)[UIApplication sharedApplication].delegate).nav.visibleViewController;

2.通过遍历当前view的响应者链 找到 View所属的控制器

- (UIViewController *)viewController:(UIView *)view
    for (UIView *next = view; next; next = next.superview) {
        UIResponder *responder = [next nextResponder];
        if ([responder isKindOfClass:[UIViewController class]]) {
            return (UIViewController *)responder;
        }
    }
    return nil;
}

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