结合一道面试题浅谈触摸事件的流程

作者: dj_rose | 来源:发表于2018-10-25 13:44 被阅读6次
    题.png
    条件:红色View 是蓝色View的子视图、蓝色View是绿色View的子视图
    问:点击超出蓝色View的红色View 会有反应吗?如果没有,有什么简单的办法让其响应红色view的事件?

    一看到这种问题,大多数人的第一想法就是重写蓝色view的hitTest方法,同时重写蓝色view的pointInside:方法。

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    {
        if ([self pointInside:point withEvent:event]) {
            return 红色view;
        }
        return [super hitTest:point withEvent:event];
    }
    
    - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
    {
        if (坐标在红色view内) {
            return YES;   
        }
        //否则返回默认的操作
        return [super pointInside:point withEvent:event];
    }
    

    通过这两个方法配合,将最佳响应者改变为红色view。

    群里有大佬就是这么回答的。然而面试官似乎并不满意,又问:有没有更简单的?

    有的同学说:改变下view的层级吧,这样最简单~

    很显然,面试官又补充了一点:不能改变现有视图层级、不能改变view的大小。

    这下就有点懵逼了。。。

    记得之前看过一篇触摸事件的文章,讲的很详细--iOS触摸事件全家桶

    于是又去翻看了下,边看边思考,面试官问的这个更简单的方法到底是想考察哪一块的知识点?

    回顾完那篇文章,简单总结下触摸事件的流程:

    系统响应 --> 传递给前台app --> 寻找事件最佳响应者(hit-testing)--> 事件的响应及在响应链中的传递
    

    不难发现,我们上面的hitTest:解决方案是在寻找事件最佳响应者(hit-testing)的过程中去改变了最佳响应者。那么,面试官所说的更简单的方法,是不是在事件最佳响应者确定了之后,事件响应过程中去拦截处理?

    答案:是的!

    可能是面试官想要的更简单的方案

    在寻找事件的最佳响应者的过程中,事件自下而上进行传递。

    UIApplication ——> UIWindow ——> 子视图 ——> ... ——> 子视图
    

    最佳响应者确定之后,事件从最佳响应者开始,自上而下的进行事件的响应及传递。
    响应者对于事件的拦截以及传递都是通过 touchesBegan:withEvent: 方法控制的,该方法的默认实现是将事件沿着默认的响应链往下传递。

    因此我们可以简单的通过重写控制器VC的touchesBegan:方法来拦截红色view的点击事件

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        UITouch *touch = [touches anyObject];
        CGPoint point = [touch locationInView:_blueView];
        if (CGRectContainsPoint(_redBtn.frame, point)) {
            [self clickTest];
        }
    }
    

    写到这里,感叹出题者对于触摸事件的考察点理解的真的是相当透彻,发人深省~

    相关文章

      网友评论

      • YJ_Wong:一般做到查看大图全屏显示之类的我都用touch began

      本文标题:结合一道面试题浅谈触摸事件的流程

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