背景:
在实际开发中,我们知道点击手机屏幕上控件,就会调用该控件相应的事件。例如,屏幕上有一个Button,我点击这个Button就会触发该Button的事件。那么,系统底层是怎么实现的呢?或者说,这整个流程是怎样的呢?下面,我们就来探索一下。
准备工作:
- 准备一个控制器
- 准备六个
UIView
准备一个父类,该父类继承
UIView
,并重写touchesBegan
的方法,打印当前UIView
的类名,六个UIView
继承这个父类。目的:减少代码量。
注意模拟器里面,每个UIView
的添加顺序,已经标明。
储备知识:
我们想要点击屏幕的控件,就要调用该控件的事件。那么为什么点击这个控件,就会调用对应事件呢?
原来,这个控件是一个响应者对象,只要是响应者对象,就能够接受并处理事件。
那么,什么是响应者对象?
在iOS
中,只有继承了UIResponder
的对象才能接受并处理事件,我们称之为”响应者对象”。
UIApplication
、UIViewController
、UIView
都继承了UIResponder
,因此他们都是响应者对象,都能够接受并且处理事件。
用户在使用App过程中,会产生各种各样的事件。在iOS
中,事件可以分为三大类型:触摸事件、加速计事件、远程控制事件。
事件传递过程:
我们知道什么是响应者对象后,我们就很清除自己要用什么控件来测试事件传递过程啦~~,只要是继承UIResponder
的都行。
事件传递原理:
发生触摸事件后,系统会将事件加入到一个由
UIApplication
管理的事件队列中。UIApplication
会从事件队列中取出最前面的事件,并将事件分发下去以便处理,先发送事件给应用程序的主窗口keyWindow
。主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件。
事件传递详细流程:
1.自己是否能接受触摸事件?
2.触摸点是否在自己身上?
3.从后往前遍历子控件,重复前面的两个步骤。
4.如果没有符合条件的子控件,那么自己就是最合适处理。
如果父控件不能接受触摸事件,那么子控件就不可能收到触摸事件
案例分析:
例子一:点击青色的UIView
。
实现流程:
UIApplication–>UIWindow–>白色UIView–>青色UIView
当点击屏幕青色UIView
时候,系统会把触摸事件加入UIApplication
事件队列中,然后分发给UIWindow
,UIWindow
会判断自己能否接受触摸事件,UIWindow
当然能接受触摸事件,那么再判断触摸点是否在自己身上,触摸点在UIWindow
上面,那么再从后往前遍历子控件。此时,UIWindow
上面的子控件只有一个,就是白色的UIView
。那么,判断白色UIView
是否能接受触摸事件,再判断触摸点是否在自己身上,满足两个条件,再遍历子控件。先判断浅蓝色的UIView
,浅蓝色的UIView
能接受触摸事件,但是触摸点不在他的身上,所以不是当前的控件。那么继续遍历青色的UIView
,能接受触摸事件,触摸点也在自己身上,此时,当前青色的UIView
没有子控件了,那么他就是最合适响应者了。
例子二:点击粉红色的UIView
(浅蓝色的UIView
关闭用户交互,即userInteraction
设置为NO
)
实现流程:
点击分红色UIView
,系统把触摸事件加入UIApplication
事件队列中,然后把事件分发给UIWindow
,UIWindow
满足条件,遍历白色的UIView
,白色UIView
满足条件。先遍历浅蓝色的UIView
,浅蓝色的UIView
自己不能接受触摸事件,因为关闭了用户交互,所以触摸点也不在自己身上。再遍历青色的UIView
,青色的UIView
有能接受触摸事件,但是触摸点也不在青色的UIView
上面。此时最适合的响应者就是白色的UIView
。
所有UIView
都打开用户交互时候:
当浅蓝色UIView
关闭用户交互,其余UIView
正常时候:
总结:
根据事件传递的原理,逐层寻找满足条件的控件,就能找到响应者对象。切记,遍历子控件时候,是从后往前遍历。