iOS事件传递和响应者链条

最近在面试中看到有个关于事件传递和响应者链条的知识点,自己之前了解的不是特别清楚,因此特意查找了相关资料,梳理了下这个知识点,特此记录下,以便后续使用。

遇到问题是:如果一个按钮的范围超出了父控件的范围,问这个按钮是否能显示全,以及点击按钮是否能正常响应?如果不能怎么处理能让它响应。

这个场景在开发中也比较常见,问题描述如下图所示:


从图中可以看出,黄色按钮虽然大小超出了父控件的范围,但是还是能正常显示。点击黄色按钮和绿色按钮相交的地方,可以正常响应,但是点击黄色按钮和绿色按钮不相交的地方就没有反应了。

造成这样的原因实际上就是事件的传递和响应者链条的原因。下面来说为什么

  1. 用户点击屏幕触发的是事件,但是屏幕上有那么多控件,怎么确定点击的是哪个控件,以及点击的事件由哪个控件响应
  2. 这个问题实际就是考察苹果事件的传递和响应者链条的知识
  3. 事件的传递是从下往上传递的;点击屏幕的事件由系统获取到传递到应用程序的AppDelegate,再传递到window,再到root ViewController的view,再到view的子视图这样一级一级传下去的
  4. 响应者链条刚好和事件传递方向相反,是从上往下传递的,先看最上边的能否响应事件,如果不能响应找父控件,一直类推,找到最后如果都不能响应事件就把事件移除

找的过程大概如下代码:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    if (!self.isUserInteractionEnabled || self.isHidden || self.alpha <= 0.01) {
        return nil;
    }
    if ([self pointInside:point withEvent:event]) {
        for (UIView *subView in [self.subviews reverseObjectEnumerator]) {
            CGPoint convertedPoint = [subView convertPoint:point fromView:self];
            UIView *hitTestView = [subView hitTest:convertedPoint withEvent:event];
            if (hitTestView) {
                return hitTestView;
            }
        }
        return self;
    }
    return nil;
}

如果想让黄色的按钮响应点击事件,从上边代码可以看出,需要把父控件的hitTest方法中的,判断点击的点,是否在当前试图的判断注释掉,才能执行到子视图的判断中。

因此:如果想让黄色视图还能响应事件,需要重写父视图的hitTest方法,并把判断点击的点是否在视图内的判断注释掉就可以了




猜你喜欢

转载自blog.csdn.net/miaogehehe/article/details/79399336