目录

一、iOS中的事件

二、实践

三、iOS中事件的产生与传递

四、事件响应链

五、例子

六、区别


本文章为学习的总结文档,如有转载,侵权请联系作者。

按照事件顺序,事件的生命周期是这样的:事件的产生和传递 - > 找到合适的view后进行事件的处理

一、iOS中的事件

iOS中的时间可以分为3大类:

  • 触摸事件
  • 加速计事件
  • 远程控制时间

我们这里主要是讨论的是触摸事件。

首先我们先了解一下响应者对象(UIResponder)。

在iOS中不是任何对象都能处理事件的,只有继承了UIResponder的对象才能接受并处理事件。UIApplication、UIView等类都继承了UIResponder类,UIWindow和UIKit中的控件因为继承了UIView,所以也间接继承了UIResponder类,这些类的实例都可以当作响应者。

二、实践

首先我们先来做一个demo实现,创建一个视图,点击红色圆形区域会产生触摸事件,点击灰色区域不会产生触摸事件。

这时候我们就需要两个重要的方法了:

//最终哪个视图响应事件, 将哪个视图返回;
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;   // recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system//判断某个点击位置是否在当前视图内;
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;   // default returns YES if point is in bounds

上述的实践代码为:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {if (self.hidden == YES || self.alpha < 0.01) {//0.01临界值return nil;}if ([self pointInside:point withEvent:event]) {__block UIView *view = nil;///遍历当前视图的subviews[self.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {//转换坐标CGPoint thePoint = [self convertPoint:point toView:obj];//子视图调用view = [obj hitTest:thePoint withEvent:event];if (view) {*stop = YES;}}];if (view != nil) {return view;}else {return self;}}else {///点击区域不在当前视图范围内, 不要响应return  nil;}
}- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {CGFloat x = point.x;CGFloat y = point.y;CGFloat centerX = self.center.x;CGFloat centerY = self.center.y;///点击点与空间中心点距离double twoPointOffset = sqrt(pow((x - centerX), 2) + pow(y - centerY, 2));//判断是否在圆形区域内if (twoPointOffset <= self.frame.size.width / 2) {return YES;}return NO;
}
  • 第一步:首先创建一个.m文件,让其继承UIButton,然后在该文件中实现上述的两个方法(hitTest和pointInside)
  • 第二步:然后我们在ViewController创建该文件的button,即可实现点击红色圆形区域可以响应点击事件,灰色区域不可以响应点击事件,绿色按钮是一个正常的button按钮,用来作对比。

实验结果 :

接下来我们就来讨论一下iOS事件的产生与传递

三、iOS中事件的产生与传递

3.1 事件的产生

  • 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列,为什么是队列而不是栈?因为队列的特点是FIFO,即先进先出,先产生的事件先处理才符合常理,所以把事件添加到队列。
  • UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)。
  • 主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件,这也是整个事件处理过程的第一步。找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理。

3.2 事件的传递

事件传递:自上而下的由UIApplication开始,一路往最具体的View查找,直到找到最应该处理并且能够处理事件的那个控件。

  • 触摸事件的传递是从父控件传递到子控件
  • UIApplication -> window -> 寻找处理事件合适的view

注: 如果父视图不接受触摸事件(userInteractionEnabled = NO),那么子视图也接收不到触摸事件。如果设置一个控件的透明度<0.01,会直接影响子控件的透明度。alpha:0.0~0.01为透明。视图隐藏起来也是不会产生触摸事件的(hidden = YES.)。

总结一下:

  • 点击一下UIView或产生一个触摸事件,这个事件会被添加到UIApplication管理事件队列中
  • UIApplication会从事件队列中取出最前面的事件,把事件A传递给UIWindow
  • UIWindow会在视图层级中找到合适的View,来实现触摸事件,至此第一步完成了。

3.3 如何寻找最合适的view

应用如何找到最合适的控件来处理事件?

  1. 主窗口接收到应用程序传递过来的事件后,首先判断自己能否接手触摸事件。如果能,那么在判断触摸点在不在窗口自己身上

  2. 如果触摸点也在窗口身上,那么窗口会从后往前遍历自己的子控件(遍历自己的子控件只是为了寻找出来最合适的view)

  3. 遍历到每一个子控件后,又会重复上面的两个步骤(传递事件给子控件,1.判断子控件能否接受事件,2.点在不在子控件上)

  4. 如此循环遍历子控件,直到找到最合适的view,如果没有更合适的子控件,那么自己就成为最合适的view。

  5. 找到最合适的view后,就会调用该view的touches方法处理具体的事件。所以,只有找到最合适的view,把事件传递给最合适的view后,才会调用touches方法进行接下来的事件处理。找不到最合适的view,就不会调用touches方法进行事件处理。

注: 之所以会采取从后往前遍历子控件的方式寻找最合适的view只是为了做一些循环优化。因为相比较之下,后添加的view在上面,降低循环次数。

四、事件响应链

响应链是由多个响应者对象连接起来的链条。

响应链:当找到那个最应该处理并且能够处理事件的那个控件以后,如果这个控件确实处理了这个事件,那么这个事件的就到此处理完毕,但是很有可能出现的情况是,虽然这个控件最应该处理,也能够处理事件,但是它并没有处理事件,那么这时这个事件就要传给下一个响应者处理,下一个响应者还不处理,那就再下一个,这个事件就沿着这条响应者链条找直到响应者确实处理了这个事件(并中断了事件传递,就是在touch方法里没有调用下一个响应者的touch方法)为止。

  1. 从上图就可以一般响应链是由视图UIView构成的
  2. 一个视图的下一个响应者是它视图控制器(UIViewController)(如果有的话),然后再转给它的父视图(Super View);
  3. UIApplication是一个响应者链的终点,它的下一个响应者指向nil,以结束整个循环。

五、例子

如果我点击了view E,那么他的整个hittest view流程是什么样的呢?

  1. view A是UIWindow的根视图,因为UIWindow对象会首先对A的进行hittest
  2. 用户点击的范围是在A的范围内的,因此pointInside会返回YES,这时我们会继续搜索A的子视图
  3. 我们发现它是由两个视图的,一个是B,一个是C,但是点击的范围不在B的上面,因此B的pointInside返回的是NO,对应的hitTest:withEvent:返回nil;点击的范围是在C的上面,因此pointInside返回的是YES,这是我们会继续搜索C的子视图
  4. C也是有两个子视图。一个是D,一个是E,但是点击的范围不在B的上面,因此B的pointInside返回的是NO,对应的hitTest:withEvent:返回nil;点击的范围是在E的上面,因此pointInside返回的是YES,这是我们会继续搜索E的子视图
  5. 但是我们发现E的是没有子视图的,因此hitTest:withEvent:会将E返回,在往回回溯,就是C的hitTest:withEvent:返回E--->>A的hitTest:withEvent:返回E。

六、区别

事件的传递路径和响应者链条的路径并不是同一条路从两头走的关系。首先,事件传递时候除了最开始的UIApplication,一路都是在查找下一个更应该响应的UIView,而响应者链条除了考虑UIView以外还有其他的UIResponder,例如UIViewController;其次,事件传递会考虑同级UIView之间的关系,就是如果一个UIView有多个子View,那么哪个是更应该响应的View,而响应者链条则不会考虑同级View之间的关系,一个View的下一个响应者并不会考虑除了自己以为其它适合响应的同级View,而是之间考虑它的父View或者是控制器。

参考文档:iOS之事件的传递

学习UI事件传递 - iOS相关推荐

  1. Android UI事件传递就是这么个事儿

    正文 ###聊聊UI事件传递 什么是UI事件? 触摸屏幕中UI控件的那一刻即为事件发生 MotionEvent对象包含了所有的触摸事件,如触摸的位置.多指触摸等 MotionEvent描述了当前的操作 ...

  2. vue学习:事件传递(冒泡和捕获),事件委托,jquery中的事件委托,$event 获取元素,vue事件修饰符

    事件传递 ----冒泡和捕获 DOM事件标准定义了两种事件流,这两种事件流分别是捕获和冒泡. 和许多Web技 术一样,在它们成为标准之前,Netscape和微软各自不同地实现了它们.Netscape选 ...

  3. Android 事件传递机制总结

    Android 事件传递机制总结 Android View虽然不是四大组件,但是其重要程度堪比四大组件.初级工程师到中高级工程师,这些都是很重要的,因为事件分发机制面试也会经常被提及,如果我们能get ...

  4. Unity3D插件 Doozy UI 学习(二):与DoozyUI的事件传递

    前言 为了能让DoozyUI与项目本身可以兼容,至少需要做到以下两点: 1.通过DoozyUI 触发一个自定义的事件(比如通过点击按钮来开始游戏). 2.通过其他模块的事件来触发DoozyUI(比如游 ...

  5. Android学习笔记--处理UI事件

    Handling UI Events 在Android里, 有不只一种方式可以截获用户与你的应用程序交互的事件. 在你的界面上处理事件时,你需要捕获用户与某个View实例交互时所产生的事件.View类 ...

  6. iOS学习9_事件分发amp;响应链

    iOS的三种事件:触摸事件/运动事件/远程控制事件 typedef enum { UIEventTypeTouches, UIEventTypeMotion, UIEventTypeRemoteCon ...

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

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

  8. iOS开发 - 事件传递响应链

    序言 当我们在使用微信等工具,点击扫一扫,就能打开二维码扫描视图.在我们点击屏幕的时候,iphone OS获取到了用户进行了"单击"这一行为,操作系统把包含这些点击事件的信息包装成 ...

  9. iOS 中的事件传递和响应机制 - 实践篇

    注:根据史上最详细的iOS之事件的传递和响应机制-实践篇重新整理(适当删减及补充). 示意图说明:白色 view 是蓝色 view 的父视图:蓝色 view 是橙色 view 的父视图. 需求一:点击 ...

最新文章

  1. 各大厂分布式链路跟踪系统架构对比
  2. 上海AI高地雏形初现 徐汇区抢占产业潮头
  3. ebs和java哪个前景好_EBS与实例存储的好处(反之亦然)[关闭]
  4. msp430入门编程11
  5. .NET混淆器 Dotfuscator使用教程三:保护你的应用之检查受保护的程序集
  6. junit runner_了解JUnit的Runner架构
  7. php 动态图表,excel实现动态图表的3种方法是什么
  8. 【转】XSD (xml Schema Definition)
  9. 中文乱码翻译器在线翻译_如何将芬兰语翻译成中文?这两种方法你得会
  10. 红黑所-1996-2011年中国黑客大事记
  11. OpenMP4.0: #pragma openmp simd实现SIMD指令优化(ARM,X86,MIPS)
  12. java wsdl文件生成_Spring Web Services 生成 WSDL 文件
  13. Mac小白必备技巧4—Mac文件管理器需要的快捷键有什么?
  14. 读书笔记:《人工智能》
  15. 面试题,微信红包为啥不能撤回?
  16. Ctrl+26字母组合快捷键,分分钟变成办公室大表哥
  17. 字典遍历时不能修改字典元素
  18. ABP 部署遇到的问题(记录)
  19. git与github从入门到精通
  20. 一招解决LoadRunner不能录制脚本(录制脚本为空)问题

热门文章

  1. 破解闲鱼收货源代码 详细解析
  2. python闲鱼爬虫_Python 爬虫爬坑路(二)——B站图片,咸鱼的正确 GET 姿势
  3. vue-cli报错:getaddrinfo enotfound locahost
  4. win10系统下我的电脑右键没有属性
  5. 网站搭建难题:网站重复发布内容相似的同类产品-重复内容 duplicate content
  6. python语言及应用
  7. Pygame飞机大战一个简单的双人模式测试
  8. DroidPlugin代码分析(三) 占坑、动态注册
  9. html中什么表示下拉列表,html中select标签(下拉列表)的详细介绍
  10. 微信小程序分享图片给微信好友