一、事件起因

  最近在开发一版本的需求中,遇到一个问题,需要在一个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事件穿透的更多相关文章

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

    使用绝对定位元素,让元素A完全盖住元素B时,如何通过元素A来响应元素B的事件呢? 上图可以用下面的SVG代码来实现: <svg width="200" height=&quo ...

  2. 手机端 zepto tap事件穿透

    什么是事件穿透? 点击上面的一层时会触发下面一层的事件 ”google”说原因是“tap事件实际上是在冒泡到body上时才触发”,也就是Zepto的tap事件是绑定在document上的,所以会导致 ...

  3. iOS之事件穿透

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

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

    如何让触摸事件穿透一个View 偶然间发现,如何屏蔽或者让触摸事件穿透一个view是一个很简单的事情. 现象: 源码: // // ViewController.m // UserInteractio ...

  5. [原创]实现多层DIV叠加的js事件穿透

    Flash里面有个很好的特性是,一个容器里,不存在实际对象的部分,不会阻拦鼠标事件穿透到下一层. 前端就不一样了,两个div层叠以后,上层div会接收到所有事件(即使这个div里面内容是空的,没有任何 ...

  6. vue中阻止事件穿透的方法

    默认情况下,事件在h5页面会穿透传递,比如一div里面套一个div,点击上层div,下层div也会响应 要阻止事件穿透,使用event.stopPropagation(); 代码示例: <div ...

  7. CSS实现事件穿透与背景图不跟随滚动条

    1. 事件穿透属性:pointer-events: none  // auto默认值.none:不捕捉target事件(实现穿透) 用途:当需要使用透明遮罩并且允许点击遮罩下方元素时,或需要使用背景容 ...

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

    经常用到多个透明图片层叠,但又需要获取不同图片的点击事件,本文实现图片透明区域穿透点击事件 实现人体各个部位点击 - (BOOL) pointInside:(CGPoint)point withEve ...

  9. UGUI 事件穿透规则

    UGUI事件分为两大类:点击和拖拽. 点击包括 pointerdown, pointerup. 拖拽包括 begindrag, drag, enddrag. 点击事件无穿透:只会被最上层UI响应,不会 ...

  10. 移动端touchstart事件穿透问题,解决方案

    [来源]:在开发移动端网站时,会经常徘徊在click和touchstart之间:因为touchstart虽然好用和快速响应:但是其缺点也是显而易见的,当我们大面积的使用touchstart的时候就会遇 ...

随机推荐

  1. Java+HTML预习笔记_20140610

    1.HTML <img> 标签 HTML <img> 标签 实例 在下面的例子中,我们在页面中插入一幅 W3School 的工程师在上海鲜花港拍摄的郁金香照片: <img ...

  2. SharePreferences概念

    概念 SharePreferences是一种轻量级的数据存储方式,它是以key-value的形式保存在 data/data//shared_prefs 下的xml文件中.通常使用它来保存应用中的一些简 ...

  3. Java入门01:环境安装与配置

    Java入门01:环境安装与配置 JDK下载 下载地址:https://www.oracle.com/cn/java/technologies/javase/javase-jdk8-downloads ...

  4. 一文读懂IoU,GIoU, DIoU, CIoU, Alpha-IoU (代码非常优雅)

    IoU就是就是我们说的交并比 Intersection over Union ,具体就是两个box的交集除以并集. 当我们计算我们的anchors 或者 proposals 与 ground trut ...

  5. 力扣400(java)-第N位数字(中等)

    题目: 给你一个整数 n ,请你在无限的整数序列 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...] 中找出并返回第 n 位上的数字. 示例 1: 输入:n = 3输出: ...

  6. Delta Lake基础介绍(商业版)

    ​简介:介绍 Lakehouse 搜索引擎的设计思想,探讨其如何使用缓存,辅助数据结构,存储格式,动态文件剪枝,以及 vectorized execution 达到优越的处理性能. 作者:李洁杏,Da ...

  7. 快速界定故障:Socket Tracer网络监控实践

    ​ 简介: Socket Tracer定位是传输层(Socket&TCP)的指标采集工具,通过补齐网络监控的这部分盲区,来达到快速界定网络问题的目标. ​ 作者 | 四忌 来源 | 阿里技术公 ...

  8. [FAQ] Fontconfig error: Cannot load default config file

      在使用一些第三方库时(比如生成图片),如果出现此提示,说明系统里缺少字体. 在 Ubuntu 上可以运行:$ apt-get install fontconfig 在 Centos 上可以运行:$ ...

  9. [FAQ] Quasar 组件 q-select 如何触发 onChange 事件

    Quasar 文档都提供了组件的可用参数和事件.方法. qSelect(q-select) 并没有 @change 事件,需要使用 @update 事件,注意用法. <q-select v-mo ...

  10. SpringBoot序列化、反序列化空字符串为null的三种方式

    一.需求:接收前端传入的""空字符串参数,有时候我们需要把它转为null SpringBoot项目 方式:①Jackson(推荐).②切面+反射.③注解+切面+反射 后两种方式,未 ...