首页 > 代码库 > 事件分发机制
事件分发机制
前言总结:
iOS的事件可以大概分为三种类型,我们会对这三种类型分别做一些介绍说明,先总结一下:
1. Milti-Touch Events 触控事件:单点、多点、手势。
2. Motion Events 传感器事件:重力、加速度。
3. Remote Control Events 远程遥控事件。
分别说明:
一:Touch Events 这个是重点,也是需要仔细说的,大家可以先想一下这样的一个过程,你点击一下屏幕,系统怎么找到我们的APP,又是怎样找到我们点击的界面,然后执行了我们的点击事件的。以前比较流行的中间凸起的标签栏,你有具体考虑过中间那个按钮的点击事件吗?超出标签栏那部分的点击事件你要不做处理,它能执行的到吗?
先说说Touch Events大致的执行过程;
点击手机屏幕 ----> UIKit 会生成一个 UIEvent事件,把UIEvent分发给当前活跃着的APP ----> 活跃着的APP被告知有事件发生后,UIApplication 单例就从事件队列中取出最新的事件,依靠 hit-Testing 找出并且返回你点击的View,让View执行事件。这样就是一个大概的过程。这里要弄清楚的就是这个hit-Testing了。给一个大概的流程图,明杰老师的;
下面就说说我们这个hit-Testing,在UIView中,有这样两个需要你特别注意的方法;
- (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
我们来说一下,说说 hitTest 方法,看着下面这张图我们说,比如说你点击了屏幕中 C 的位置:
1:点击的位置是在 RootView当中,RootView 收到hitTest消息, 先调用RootView的pointInside:withEvent方法,判断点击的点是不是在RootView中,上面的例子是在RootView中,所以pointInside:withEvent方法返回YES,接下来会遍历 RootView 的子视图 View1 和 View2。
2:View1 和 View2 都是 RootView 的子视图,都会接收到 hitTest 消息,但记得遍历的顺序是从上到下,所以先判断 View1 界面,这时候调用 View1 的pointInside:withEvent 方法,方法判断点击的点不在 View1 当中,返回 NO,这时候就会接着判断 View2,注意一点,要是这个点在我们的 View1 当中,就不再去判断 View2 了。
3:调用 View2 pointInside:withEvent ,点击的点在 View2 当中,返回 YES,这时候 View2 就像我们刚开始时候的 RootView 一样,同样的过程去遍历它的子势图 ViewB 和 ViewC,B的 pointInside:withEvent 返回的是 NO,C的 pointInside:withEvent 返回的是YES,注意这时候,C是没有了子视图的了,就不在往下去遍历,这时候的 hitTest 方法返回的View,就使我们的ViewC。
上面的过程大概就是这样,就遍历找到了点击的视图ViewC,
做个假如,假如要是点的不是 B 和 C ,则 B和 C 的 pointInside:withEvent 返回的都是NO,这时候View2就会调用自己的 hitTest 方法,并且返回的UIView就是自己 View2。
现实中的应用:
以前有仿写过闲鱼APP的标签栏,标签的样式看下面的图片,在这里我们就得处理一下中间的发布按钮,要是不做一些处理,你的点击事件在“发布”按钮找出标签栏的部分是没有效果的。
中间这一块的处理代码如下:
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ if (self.isHidden == NO) { // 将 点击的point的像素位置转换到 中间按钮 中 CGPoint newPoint = [self convertPoint:point toView:self.plusBtn]; // 如果点击的位置 newPoint 在 按钮的位置当中,就返回 按钮 if ([self.plusBtn pointInside:newPoint withEvent:event]) { return self.plusBtn; } else { return [super hitTest:point withEvent:event]; } } else { return [super hitTest:point withEvent:event]; }}
PS,太小就不放Git上了,想要这个源代码,前面有我Q,加我Q,我发Demo给你。
它还能做的多呢!
上面就是hitTest的一些概念和简单的使用,其实它能做的事还是挺多的,我把自己学习的笔记链接全都整理出来给;
iOS事件分发机制(一) hit-Testing 技术哥
iOS事件分发机制(二)The Responder Chain 技术哥
iOS触摸事件处理
史上最详细的iOS之事件的传递和响应机制
Motion Events 和 Remote Control Events:
Motion Events ,传感器加速器这两个东西我就不再说我,以前说屏幕方向的时候写过这两个东西,博客里面也有关于他们的许多的链接,我在就直接把那篇博客的链接给出来,有兴趣的可以翻一翻; 屏幕方向该知道的那些事儿
最后这个 Remote Control Events ,额...暂时没有接触过,就不说了,这个可能还得去问度娘。
事件分发机制