UINavgationBar事件穿透
一、事件起因
最近在开发一版本的需求中,遇到一个问题,需要在一个ViewController的顶部,UINavgationBar的下面放置一个View,这个View需要能够正常收到事件
将我们的View放到这个位置之后,发现底部的View、按钮等无法接受到响应
二、解决思路
1)第一次想到的是事件转发,如果控制了事件分发是不是就可以将事件想发给谁就发给谁了呢?

我们先回忆一下,事件分发的过程:
1、首先用户触摸屏幕产生触摸事件(此外还有Motion Event,Remote Event),手机系统驱动收到这个触摸事件
2、系统产生中断,进入响应触摸事件的终端程序,此时肯定是系统将事件封装为UIEvent,并发送给最前台的进程
3、进程收到这个事件之后,将其发给UIApplication进行处理
4、UIApplication 收到这个UIEvent事件之后,会进行一个事件的分发,决定将这个事件发给最终的响应者进行处理
这里涉及到两部分,建立事件响应链、沿着事件响应链处理事件

建立事件响应链,其实是寻找最合适的事件响应者(responder)的过程,步骤大概如下
首先UIApplication对象将事件发给UIWindow,UIWindow会调用从UIView 继承的 hitTest方法返回第一响应者
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
hitTest 是一个递归当用的方法,找到触摸事件的第一响应者,流程是,对Window下面的所有子View调用hitTest方法,
如果触摸点 point Inside子view中,那么相当于找到下一级,再次进行递归寻找,直到找到最终的响应者。
以上是事件寻找响应者的过程、如果第一响应者不能处理这个事件,会将这个事件沿着nextResponder逐步向上传递,进行处理
5、当找到第一响应者之后,会有响应的回调
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
如果这个响应者上绑定有手势识别器,那么手势识别器会对这个事件进行延迟、等识别
这就是UIScrollView上面按钮响应慢的原因,因为第一个touchBegan来了之后,手势识别器需要后面的事件一起判断是滑动还是点击
2)如何实现UINavgationBar事件穿透功能
我们可以通过修改寻找响应者的逻辑,来将事件抛回上层,再次递归到底层的View来实现,具体如下
首先我们继承一个UINavgationBar,修改hitTest的流程
//穿透点击事件
@objc class UICustomTouchNavigationBar: UINavigationBar {
@objc var passThroughEvent:Bool = false
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let v = super.hitTest(point, with: event)
if (passThroughEvent && v?.ignoreEvent ?? false)
{
//启用事件穿透的时候
return nil
}
return v;
}
}
var UIViewIgnoreEventKey = "UIViewIgnoreEventKey"
@objc extension UIView {
public var ignoreEvent:Bool {
get{
guard let value = objc_getAssociatedObject(self,
&UIViewIgnoreEventKey)
as? Bool else {
return false
}
return value
}
set{
objc_setAssociatedObject(self,
&UIViewIgnoreEventKey,
newValue,
objc_AssociationPolicy.OBJC_ASSOCIATION_ASSIGN)
}
}
}
我们要做的是,在UINavgationBar上面的按钮等收到事件的时候,我们不忽略;在空白的地方收到事件的时候,我们直接返回nil进行忽略
在初始化导航的时候,传入我们自定义的NavBar
- (instancetype)initWithNavigationBarClass:(nullable Class)navigationBarClass toolbarClass:(nullable Class)toolbarClass NS_AVAILABLE_IOS(5_0);
因为UINavgationBar是属于每个ViewController,也就是独立的,所以我们只需要在ViewDidLoad中启用事件穿透,并且把UINavgationBar的子View中的时间忽略标志打开,那么事件将自动传递到底层中。
三、附言
1)图片来自
https://www.jianshu.com/p/74a2f44840fa
https://www.jianshu.com/p/4155c9ffe1a8
UINavgationBar事件穿透的更多相关文章
- 支持事件穿透?使用pointer-events样式
使用绝对定位元素,让元素A完全盖住元素B时,如何通过元素A来响应元素B的事件呢? 上图可以用下面的SVG代码来实现: <svg width="200" height=&quo ...
- 手机端 zepto tap事件穿透
什么是事件穿透? 点击上面的一层时会触发下面一层的事件 ”google”说原因是“tap事件实际上是在冒泡到body上时才触发”,也就是Zepto的tap事件是绑定在document上的,所以会导致 ...
- iOS之事件穿透
前言 小伙伴们在开发中是否遇到过这样的需求呢,一个控件的某个部分被另外一个控件遮挡住,当点击这个重叠部分时,需要响应被遮盖控件的点击事件,就如下图所示 当我们点击区域3时,响应蓝色按钮的点击事件, ...
- 如何让触摸事件穿透一个View
如何让触摸事件穿透一个View 偶然间发现,如何屏蔽或者让触摸事件穿透一个view是一个很简单的事情. 现象: 源码: // // ViewController.m // UserInteractio ...
- [原创]实现多层DIV叠加的js事件穿透
Flash里面有个很好的特性是,一个容器里,不存在实际对象的部分,不会阻拦鼠标事件穿透到下一层. 前端就不一样了,两个div层叠以后,上层div会接收到所有事件(即使这个div里面内容是空的,没有任何 ...
- vue中阻止事件穿透的方法
默认情况下,事件在h5页面会穿透传递,比如一div里面套一个div,点击上层div,下层div也会响应 要阻止事件穿透,使用event.stopPropagation(); 代码示例: <div ...
- CSS实现事件穿透与背景图不跟随滚动条
1. 事件穿透属性:pointer-events: none // auto默认值.none:不捕捉target事件(实现穿透) 用途:当需要使用透明遮罩并且允许点击遮罩下方元素时,或需要使用背景容 ...
- IOS 多个ImageView图片层叠透明区域点击事件穿透
经常用到多个透明图片层叠,但又需要获取不同图片的点击事件,本文实现图片透明区域穿透点击事件 实现人体各个部位点击 - (BOOL) pointInside:(CGPoint)point withEve ...
- UGUI 事件穿透规则
UGUI事件分为两大类:点击和拖拽. 点击包括 pointerdown, pointerup. 拖拽包括 begindrag, drag, enddrag. 点击事件无穿透:只会被最上层UI响应,不会 ...
- 移动端touchstart事件穿透问题,解决方案
[来源]:在开发移动端网站时,会经常徘徊在click和touchstart之间:因为touchstart虽然好用和快速响应:但是其缺点也是显而易见的,当我们大面积的使用touchstart的时候就会遇 ...
随机推荐
- linux 性能自我学习 ———— 软中断 [五]
前言 linux 性能的自我学习. 正文 什么是软中断呢? 举一个网络的例子. linux 将中断处理过程分为两个阶段: 上半部用来快速处理中断,他在中断禁止模式下运行,注意是处理跟硬件紧密相关或时间 ...
- css 文字溢出省略号
前言 css 文字溢出后显示省略号,这是一个非常常规的操作,但是你会发现在网上很多给出的例子两行之后显示省略号,却没有用. 这是为什么呢?please look follow. 正文 在一行省略的: ...
- nginx 均衡负载
前言 在此只介绍一些nginx的简单的负载均衡. 正文 在这篇之前,请看我的nginx反向代理这一篇,是接着上面的例子写的. 我在上个例子中,分别是两个a.html 和 b.html 现在我把他们的名 ...
- 重新整理数据结构与算法(c#)—— 线索化二叉树[二十]
前言 为什么会有线索化二叉树呢? 是这样子的,二叉树呢,比如有n个节点,那么就有n+1个空指针域. 这个是怎么来的呢?比如我们假如一个节点都有左子树和右子树,那么就有2n个节点. 但是我们发现连接我们 ...
- leetcode:3. 无重复字符的最长子串
3. 无重复字符的最长子串 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例 1: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子 ...
- 对于dubbo和zookeeper的浅见
在服务器集群环境中,阿里推出的dubbo框架一直是让人仰望的存在,可如今想想,也没啥. dubbo其实就是一个调用工具,他的服务调度也就是知名的几个负载均衡算法,服务监控其实也就是有一个定时任务在定期 ...
- vue中img标签图片 加载时 与 加载失败 的处理方法
开发过程中经常需要和图片处理打交道,看了网上很多有关图片处理的方法,都是讲解得一知半解,没有比较全面的总结.下面,将简单总结一个我们通过vue去处理img标签过程中,图片加载时,与图片加载失败时的处理 ...
- Oracle对一个字符串中的数字与非数字进行分割
Oracle对一个字符串中的数字与非数字进行分割 Oracle中对一个字符串中的数字与非数字进行分割 思路很简单,就是将字符串分成数字与非数字 则只要将字符串中的数字全部换成空,就是分割后的非数字字符 ...
- 阿里云全站加速DCDN重磅发布!打造新一代加速引擎
简介: 新一代的加速引擎DCDN,安全.高效.可计算 在数字化转型变革逐步深入的当下,安全高效成为企业上云.全球化部署的关键需求. 随着应用场景复杂度不断提升.业务需求差异化发展,为了给企业提供更完善 ...
- Nacos 开源、自研、商业化三位一体战略解读
简介: Nacos作为整个阿里云原生三位战略中的核心组成部分,我们在2018年以Configserver/VIPServer/Diamond为基础通过Nacos开源输出阿里十年沉淀的注册中心和配置中心 ...