zoukankan      html  css  js  c++  java
  • iOS之事件穿透

    前言

    小伙伴们在开发中是否遇到过这样的需求呢,一个控件的某个部分被另外一个控件遮挡住,当点击这个重叠部分时,需要响应被遮盖控件的点击事件,就如下图所示


     


    当我们点击区域3时,响应蓝色按钮的点击事件,点击区域1和2时,响应红色按钮的点击事件,对于区域1和3没什么好说的,那如何让红色按钮响应区域2的点击呢?这就是笔者今天要讲的内容。

    事件传递

    大家应该都知道,事件从应用程序开始,按照从上到下的顺序(UIApplication -> UIWindow -> rootViewController -> ...)一级一级传递,并且系统在寻找最适合处理事件的控件时,是从后往前遍历子控件的(网上资料太多,不做详细阐述,请自行百度)

    上图中蓝色按钮在红色按钮之后添加,当系统寻找最适合的控件时,蓝色按钮在红色按钮之前被找到,系统发现蓝色按钮很适合处理事件,所以方法便返回了,红色按钮就没有了处理事件的机会。

    系统如何寻找最适合控件

    • 判断自己能否接受触摸事件,如果不能,返回nil
    • 判断触摸点是否在自己身上,如果不能,返回nil
    • 从后往前遍历子控件,重复上面的步骤,如果没有适合的子控件,返回自己

    我们来看看系统内部是如何实现的,笔者这里自定义了一个UIWindow,让它成为主窗口,并重写它的hitTest方法,运行之后,其事件处理功能,与系统的类似,所以系统内部大概就是这样实现的


     

    当一个控件的透明度小于某个值时,就不再响应事件,上图中0.01仅仅是为了测试,并非准确的值,要注意的就是,对于继承自UIControl的控件,还需要判断enable的值

    事件穿透

    既然系统寻找最合适控件的方法满足不了我们,那我们就重写系统的方法

    思路
    • 点击蓝色按钮的区域2,红色按钮响应事件,那肯定要重写蓝色按钮的hitTest方法
    • 在hitTest方法中,将触摸点的坐标系从蓝色按钮转换到红色按钮上,即以红色按钮左上角为原点
    • 坐标系转换后,判断触摸点是否在红色按钮上,如果是,直接返回红色按钮(严谨一点的做法是调用红色按钮的hitTest方法),如果不是,那就调用系统的方法,让系统去处理

    有了思路,那万事具备只欠东风了,接下来上东风

    新建一个类,继承自UIButton,笔者这里直接命名为BlueButton,修改sbxib中蓝色按钮的类型为BlueButton


     

    将红色按钮连线到BlueButton.m文件中,不用试了,直接连是连不了的,我们可以先在BlueButton.m中定义一个属性,前面加上IBOutlet,然后单击图中的空心圆,拖到红色按钮上就OK了


     

     

    最后,在BlueButton.m中重写蓝色按钮的hitTest方法,代码如下

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        CGPoint redBtnPoint = [self convertPoint:point toView:_redButton];
        if ([_redButton pointInside:redBtnPoint withEvent:event]) {
            return _redButton;
        }
        //如果希望严谨一点,可以将上面if语句及里面代码替换成如下代码
        //UIView *view = [_redButton hitTest: redBtnPoint withEvent: event];
        //if (view) return view;
        return [super hitTest:point withEvent:event];
    }

    来看运行结果,点击区域2时,红色按钮高亮并响应事件



     
  • 相关阅读:
    yzoj P2344 斯卡布罗集市 题解
    yzoj P2350 逃离洞穴 题解
    yzoj P2349 取数 题解
    JXOI 2017 颜色 题解
    NOIP 2009 最优贸易 题解
    CH 4302 Interval GCD 题解
    CH4301 Can you answer on these queries III 题解
    Luogu2533[AHOI2012]信号塔
    Luogu3320[SDOI2015]寻宝游戏
    Luogu3187[HNOI2007]最小矩形覆盖
  • 原文地址:https://www.cnblogs.com/fengmin/p/5799207.html
Copyright © 2011-2022 走看看