美文网首页收藏iosiOS
iOS 点击穿透上层视图响应事件

iOS 点击穿透上层视图响应事件

作者: iOS_肖晨 | 来源:发表于2018-02-10 16:16 被阅读1536次

    昨天被问到了一个问题,如下

    一个子视图能不能透过上层视图来响应自己的点击事件?如果能,怎么实现?

    这种题用脚想都是能啊,可怎么做???
    经过简单研究,发现了解决办法。如下:

    这里涉及到一个视图的方法
    - (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
    这是在UIView(UIViewGeometry)视图结构分类里面的方法,使用方法如下:

    1. 背景知识

    iOS系统检测到手指触摸(Touch)操作时会将其放入当前活动Application的事件队列,Application会从事件队列中取出触摸事件并传递给key window(当前接收用户事件的窗口)处理,window对象首先会使用hitTest:withEvent:方法寻找此次Touch操作初始点所在的视图(View),即需要将触摸事件传递给其处理的视图,称之为hit-test view。

    window对象会在首先在view hierarchy的顶级view上调用hitTest:withEvent:,此方法会在视图层级结构中的每个视图上调用pointInside:withEvent:,如果pointInside:withEvent:返回YES,则继续逐级调用,直到找到touch操作发生的位置,这个视图也就是hit-test view。

    2. 处理流程

    1. 首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内;
    2. 若返回NO,则hitTest:withEvent:返回nil;
    3. 若返回YES,则向当前视图的所有子视图(subviews)发送hitTest:withEvent:消息,所有子视图的遍历顺序是从top到bottom,即从subviews数组的末尾向前遍历,直到有子视图返回非空对象或者全部子视图遍历完毕;
    4. 若第一次有子视图返回非空对象,则hitTest:withEvent:方法返回此对象,处理结束;
    5. 如所有子视图都返回非,则hitTest:withEvent:方法返回自身(self)。

    3. 使用

    直接参考代码

    // 在父视图中实现方法
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        // 1.这是当前点击的视图,如果没有找到合适的响应操作的视图,则直接返回这个
        UIView *view = [super hitTest:point withEvent:event];
    
        // 2.将父视图坐标转成我想要响应事件的视图的坐标
        CGPoint buttonPoint = [self convertPoint:point toView:self.button];
    
        // 3.判断该坐标是否在视图内部,如果是,则返回该视图
        if ([self.button pointInside:buttonPoint withEvent:event]) {
            return self.button;
        }
        return view;
    }
    

    代码写起来也是简单明了,但有几个注意事项,如下:

    1. 设置hidden = YES;仍然是可以通过该方法响应事件。
    2. 设置alpha = 0.001;也是可以通过该方法响应事件。
    3. 子视图的 origin 即使超出父视图的范围也是可以响应事件。
    4. 设置userInteractionEnabled = NO;则不可以响应事件了。

    这种方式可以做出很多风骚的操作,就看各位的想象力了~

    相关文章

      网友评论

        本文标题:iOS 点击穿透上层视图响应事件

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