背景:

在实际开发中,我们知道点击手机屏幕上控件,就会调用该控件相应的事件。例如,屏幕上有一个Button,我点击这个Button就会触发该Button的事件。那么,系统底层是怎么实现的呢?或者说,这整个流程是怎样的呢?下面,我们就来探索一下。


准备工作:

  1. 准备一个控制器
  2. 准备六个UIView
  3. 准备一个父类,该父类继承UIView,并重写touchesBegan的方法,打印当前UIView的类名,六个UIView继承这个父类。目的:减少代码量。

注意模拟器里面,每个UIView的添加顺序,已经标明。


储备知识:

我们想要点击屏幕的控件,就要调用该控件的事件。那么为什么点击这个控件,就会调用对应事件呢?

原来,这个控件是一个响应者对象,只要是响应者对象,就能够接受并处理事件。

那么,什么是响应者对象

iOS中,只有继承了UIResponder的对象才能接受并处理事件,我们称之为”响应者对象”。

UIApplicationUIViewControllerUIView都继承了UIResponder,因此他们都是响应者对象,都能够接受并且处理事件。

用户在使用App过程中,会产生各种各样的事件。在iOS中,事件可以分为三大类型:触摸事件、加速计事件、远程控制事件。


事件传递过程:

我们知道什么是响应者对象后,我们就很清除自己要用什么控件来测试事件传递过程啦~~,只要是继承UIResponder的都行。

事件传递原理:

  1. 发生触摸事件后,系统会将事件加入到一个由UIApplication管理的事件队列中。
  2. UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,先发送事件给应用程序的主窗口keyWindow
  3. 主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件。

事件传递详细流程:

1.自己是否能接受触摸事件?

2.触摸点是否在自己身上?

3.从后往前遍历子控件,重复前面的两个步骤。

4.如果没有符合条件的子控件,那么自己就是最合适处理。

如果父控件不能接受触摸事件,那么子控件就不可能收到触摸事件


案例分析:

例子一:点击青色的UIView

实现流程:

UIApplication–>UIWindow–>白色UIView–>青色UIView

当点击屏幕青色UIView时候,系统会把触摸事件加入UIApplication事件队列中,然后分发给UIWindowUIWindow会判断自己能否接受触摸事件,UIWindow当然能接受触摸事件,那么再判断触摸点是否在自己身上,触摸点在UIWindow上面,那么再从后往前遍历子控件。此时,UIWindow上面的子控件只有一个,就是白色的UIView。那么,判断白色UIView是否能接受触摸事件,再判断触摸点是否在自己身上,满足两个条件,再遍历子控件。先判断浅蓝色的UIView,浅蓝色的UIView能接受触摸事件,但是触摸点不在他的身上,所以不是当前的控件。那么继续遍历青色的UIView,能接受触摸事件,触摸点也在自己身上,此时,当前青色的UIView没有子控件了,那么他就是最合适响应者了。

例子二:点击粉红色的UIView(浅蓝色的UIView关闭用户交互,即userInteraction设置为NO)

实现流程:
点击分红色UIView,系统把触摸事件加入UIApplication事件队列中,然后把事件分发给UIWindowUIWindow满足条件,遍历白色的UIView,白色UIView满足条件。先遍历浅蓝色的UIView,浅蓝色的UIView自己不能接受触摸事件,因为关闭了用户交互,所以触摸点也不在自己身上。再遍历青色的UIView,青色的UIView有能接受触摸事件,但是触摸点也不在青色的UIView上面。此时最适合的响应者就是白色的UIView


所有UIView都打开用户交互时候:

IOS点击事件传递 ios 事件传递过程_控件


当浅蓝色UIView关闭用户交互,其余UIView正常时候:

IOS点击事件传递 ios 事件传递过程_事件传递_02


总结:

根据事件传递的原理,逐层寻找满足条件的控件,就能找到响应者对象。切记,遍历子控件时候,是从后往前遍历。