注:根据史上最详细的iOS之事件的传递和响应机制-实践篇重新整理(适当删减及补充)。

示意图说明:白色 view 是蓝色 view 的父视图;蓝色 view 是橙色 view 的父视图。

  1. 需求一:点击重叠区,只有蓝色 view(既父视图)响应事件。

    一个最简单的办法是将子视图的 isUserInteractionEnabled 设置为 false ;也可以在子视图的 hitTest(_:with:) 方法里面返回 nilsuperview ,可以达到同样的效果。


  2. 需求二:点击屏幕上的任意地方;只有蓝色 view 响应事件。

    一个最简单的办法是在蓝色 view 的 hitTest(_:with:) 方法里返回 self 。当事件传递到蓝色 view 时,返回自己做为最适合触发事件的控件。


  3. 需求三:点击橙色 view 的任意地方,蓝色 view(既父视图)响应事件。

    难点在于点击非重叠区时,蓝色 view 不能接收到事件。为什么会出现这种情况呢?回顾一下 “原理篇 - 如何寻找最适合的控件来处理事件” 就会发现,一个控件想要接收事件需要满足两个条件:

    1. 判断自己能否触发事件;
    2. 判断触摸点是否在自己身上point(inside:with:) )。

    根据第二点,我们在点击非重叠区时,触摸点不在自己(蓝色 view)身上,因此不能够接收事件。

    再回顾一下这一节的要点:触摸事件传递的过程是从父控件传递到子控件的,如果父控件也不能接收事件,那么子控件就不可能接收事件。

    那应该怎么做呢?关键还是在第二点上(判断触摸点是否在自己身上),这个方法返回的是一个 Bool 类型的值,换句话说,无论点是否在自己身上,只要让这个方法返回 true,就可以让蓝色 view 接收事件。

    /// BlueView.swift
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {// 首先正常返回,// 如果点不在自己身上,则判断点是否在橙色 view 身上。// 注:此时的 subviews.first 代表橙色 view。return super.point(inside: point, with: event) || subviews.first!.frame.contains(point)
    }
    复制代码

    这样做是可以的,也最简单。但有一个问题,那就是如果橙色 view 也实现了 touches(_:with:) ,这时候是橙色 view 触发事件而不是蓝色 view。为什么呢?

    因为只要判断符合了条件,事件就会传递到橙色 view,而触摸点正好在橙色 view 身上,因此是橙色 view 触发了事件。

    不过一般来说,有这种需求的子控件(橙色 view)都不会自己实现事件而是交给父控件(蓝色 view)去处理。所以如果不想考虑这么多的话,可以直接用上面的方法。但是如果想屏蔽掉子控件事件的触发的话,还是有办法解决的。

    解决的办法就是拦截橙色 view 接收事件,只要在 BlueView.swift 中重写 hitTest(_:with) 方法,返回指定的 view 来做为最适合处理事件的控件就可以了。

    /// BlueView.swift
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {let hitView = super.hitTest(point, with: event)// 如果点在橙色 view 的身上,返回自己(蓝色 view),不在则正常返回。// 注:此时的 subviews.first 代表橙色 view。return subviews.first!.frame.contains(point) ? self : hitView
    }
    复制代码

    这样一来,事件就不会传递到橙色 view 了,只要点在橙色 view 身上,我就返回它的父视图(蓝色 view);如果不在,就正常返回(点击了蓝色 view 还是蓝色 view 触发事件;点击了白色 view 则触摸点不在蓝色 view 身上,此时白色 view 接收事件。)


  4. 需求四:点击重叠区时,橙色 view 和蓝色 view 都响应事件。

    一个最简单的办法是在我们重新实现橙色 view 的 touches(_:with:) 方法后,调用 super.touches(_:with:) 让它继续将事件传递给下一个响应者(蓝色 view)接收并处理事件。

    /// OrangeView.swift
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {print("Orange: \(#function)")// 继续将事件传递给下一个响应者 (此时是蓝色 view)super.touchesBegan(touches, with: event)
    }/// BlueView.swift
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {print("Blue", #function)
    }
    复制代码

  5. 需求五:正常响应,点击橙色 view 是橙色 view 响应事件;而点击蓝色 view 是蓝色 view 响应事件。

    可以说是经常出现的需求了,有时候我们需要处理超出父视图区域的子视图事件,但是点击超出区域的部分却不能响应事件。那要怎么做呢?

    其实这个问题在需求三的第一个示例中已经解决了,这里不再赘述。

转载于:https://juejin.im/post/5c43154a6fb9a049f5717259

iOS 中的事件传递和响应机制 - 实践篇相关推荐

  1. iOS中触摸事件传递和响应原理

    系统响应阶段 1.手指触碰屏幕,屏幕感受到触摸后,将事件交由IOKit来处理. 2.IOKIT将触摸事件封装成IOHIDEvent对象,并通过mach port传递给SpringBoard进程. ma ...

  2. 屏幕旋转之后的触摸坐标_iOS 中触摸事件传递和响应原理

    作者:雪山飞狐_91ae 链接:https://www.jianshu.com/p/4aeaf3aa0c7e 系统响应阶段 1.手指触碰屏幕,屏幕感受到触摸后,将事件交由IOKit来处理. 2.IOK ...

  3. vbs按钮传递过程_iOS面试题:事件传递和响应机制

    1. 事件的产生 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中,为什么是队列而不是栈?因为队列的特点是FIFO,即先进先出,先产生的事件先处理才符合常理,所以把 ...

  4. IOS中触摸事件学习

    IOS中触摸事件学习 1. 事件的声明周期 2. 系统相应阶段 3. APP响应阶段 4. 触摸.事件.响应者 4.1 UITouch(触摸) 4.2 UIEvent(事件真身) 4.3 UIResp ...

  5. Event Handling Guide for iOS——由触摸事件传递想到的

    先帖官方文档地址 https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlin ...

  6. wap开发问题总结(ios中click事件无法触发、身份证分隔、倒计时、验证码分隔等)

    需求背景:用户在通过短信验证码方式注册或者登陆时,存在二次卡场景(运营商回收原机主不用的手机号,存放三个月后,再次开放给新机主),导致新机主可以登录原机主账号,如果原机主不换绑手机.二次卡判断条件:手 ...

  7. IOS中的事件响应链,事件冒泡机制基本了解

    本文主要讲解IOS中事件响应链,即事件冒泡机制.做过web开发的同学应该知道js事件冒泡是从主响应元素一层一层的向父级冒泡事件,在ios亦是如此,但是不同是ios中,如果冒泡链中有一方对事件进行响应处 ...

  8. iOS之深入解析事件传递的响应链

    一.UIResponder App 使用响应者对象接收和处理事件,只有继承 UIResponder 的类,才能处理事件. UIApplication.UIView.UIViewController 都 ...

  9. iOS —— 触摸事件传递及响应与手势

    iOS 的事件分为三种,触摸事件(Touch Event).加速器事件(Motion Events).远程遥控事件(Remote Events).这些事件对应的类为UIResponder.本文只探究触 ...

最新文章

  1. 正试图在 os 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码......
  2. AR(Augmented Reality)学习
  3. 通信系统之信道(四)
  4. Django-RQ介绍
  5. 转:Google论文之三----MapReduce
  6. 使用Istio进行多集群部署管理:单控制平面 Gateway 连接拓扑
  7. avatar.php uid,phpcms函数库中获取会员头像方法get_memberavatar()有时无效问题
  8. linux gcc编译C程序 分享
  9. 转贴:电子商务如何提升网站转化率之:谷歌9条
  10. matlab实现线性规划
  11. java中的页面:JSP(已过时)
  12. windows2008 服务器时间格式改不过来_我用VNPY 1天时间搭建自主量化交易(程序化交易)平台...
  13. 一款网盘软件应该具备哪些功能?
  14. 计算机网络超详细笔记(三):数据链路层
  15. 软件安装教程1——Neo4j下载与安装
  16. 微信小程序插件安装Vant有赞组件库
  17. ORA-20011 ORA-29913 KUP-11024
  18. Win11磁盘清理在哪打开?
  19. ZJM与生日礼物【字典树】
  20. Translate Aticle

热门文章

  1. VR如何巧妙填补传统数据视觉化的漏洞
  2. CentOS 7 搭建docker仓库
  3. 【编程练习】C语言debug合集
  4. SendDlgItemMessage
  5. Spring Cloud--Honghu Cloud分布式微服务云系统—System系统管理
  6. MATLAB R2018a 输入中文却显示方框问号的问题
  7. 转载: Qt 学习之路 2归档
  8. linux - command - iftop
  9. 《JAVA与模式》之模板模式(转载)
  10. 算法导论 6.2-5