转载:事件穿透

前言

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

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

事件传递

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

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

系统如何寻找最适合控件

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

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

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

事件穿透

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

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

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

新建一个类,继承自UIButton,笔者这里直接命名为BlueButton,修改sb\xib中蓝色按钮的类型为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时,红色按钮高亮并响应事件

文/codingZero(简书作者)
原文链接:http://www.jianshu.com/p/0bece5f27650
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

时间: 2024-12-22 01:55:00

转载:事件穿透的相关文章

IE8,input事件穿透

连续加班一个半月,项目昨天晚上12:08终于上线了:然后处理了一些新发现的bug:一直熬到凌晨五点半才吃点宵夜回家睡觉.然后下午这会过来上班:回想昨晚的场景,真的跟打仗一样..然后发现了一个比较有意思的bug:称之为"事件穿透"!,问题只在纯IE8浏览器下重现(IE9,10,11的的IE8模式切换不重新). 场景大概是这样的:首页有一个浮动的登录框:然后页头有一个导航(有链接),下面还有一个轮播图,而且有链接:如下图所示: 然后,IE8下,当你准备在输入框输入时,忽然发现点了一下,页面

如何让触摸事件穿透一个View

偶然间发现,如何屏蔽或者让触摸事件穿透一个view是一个很简单的事情. 现象: 源码: // // ViewController.m // UserInteraction // // Created by YouXianMing on 14/10/23. // Copyright (c) 2014年 YouXianMing. All rights reserved. // #import "ViewController.h" @interface ViewController () @

支持事件穿透?使用pointer-events样式

使用绝对定位元素,让元素A完全盖住元素B时,如何通过元素A来响应元素B的事件呢? 上图可以用下面的SVG代码来实现: <svg width="200" height="180"> <rect x="50" y="50" width="50" height="50" fill="#f34b5b" onclick="alert('Clicked

屏幕事件穿透和拦截分析

事件穿透和拦截机制同样并不是deviceone平台独有的,这个机制几乎是所有和UI相关的技术都共有,了解一下非常有必要.我们会以一个简单的例子来描述事件处理机制运行的过程. 屏幕事件处理机制 我们先假定是手机屏幕显示一个UI,里面包括了4个View,这些View都是树状结构,父View下包含一个或多个子View,其中最上层的View和屏幕大小是一致的,参考下图: 我们可以看到view1有一个子节点view2,view2包含2个子节点view3和view4. 假如我们点击屏幕一个位置,会产生一个事

Unity中uGUI的控件事件穿透逻辑

1.正常来说Image和Text是会拦截点击事件的,如果添加EventTrigger的话,就可以响应对应的交互事件. 2.如果Image和Text是一个Button的子控件,那么虽然其会显示在Button上面,但是并不会拦截点击事件.除非是Selectable的,否则子控件不会影响到父控件的点击. 3.如果是跨Panel或者是同级的Image和Text,是会拦截点击事件的,即如果Image在某个Button之上,那么点击Image的事件不会穿透给Button. 4.如果在3的情况下想忽略点击事件

cocos 新手引导之事件穿透

游戏中新手引导 一般都是通过蒙版然后突出某一位置,并配合相应动画来实现的.遮罩层有两个需求,一是可以挖个洞,二是这个洞事件可以穿透, 其他区域不能穿透.如果事件不能穿透,那就需要做很多工作来处理相应的响应.穿透之后实际点的就是那个位置,只需要处理遮罩部分应该有的行为 研究了cocos2dx 3.1 的事件系统,发现虽然不能原生支持,但我们可以简单扩展一下就能达到我们的目的 下边是源代码: LayoutTouchBreak.h class LayoutTouchBreak: public Layo

iOS 使点击事件穿透透明的UIView

如图: 悬浮的三个按钮下方有一个可以点击的灰色区域,但是点击按钮之间的透明区域, 这三个按钮的contentView会响应这个点击事件,这时候需要让这个contentView不响应这个点击事件. 解决方法如下(将此方法增加到这个contentView类中即可): - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ UIView *hitView = [super hitTest:point withEvent:event];

IOS 多个ImageView图片层叠透明区域点击事件穿透

经常用到多个透明图片层叠,但又需要获取不同图片的点击事件,本文实现图片透明区域穿透点击事件 实现人体各个部位点击 [objc] view plain copy - (BOOL) pointInside:(CGPoint)point withEvent:(UIEvent *)event { CGPoint shoulderPoint = [self getNewPoint:point SetImage:shouldImage]; if(CGRectContainsPoint(shouldImage

UGUI 事件穿透规则

UGUI事件分为两大类:点击和拖拽. 点击包括 pointerdown, pointerup. 拖拽包括 begindrag, drag, enddrag. 点击事件无穿透:只会被最上层UI响应,不会向下层传递. 拖拽事件半穿透:透过上层UI直到遇见实现了拖拽事件的第一个UI,并且不会向下层传递. 举例:一堆重叠在同一位置的按钮按层次从上到下依次为A,B,C,D 1,只有最上层的按钮A能收到点击事件.下面的全部被挡住了. 2,给B实现 IBeginDrag, IDrag, IEndDrag接口,