事件分发机制

前言总结

    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 ,额...暂时没有接触过,就不说了,这个可能还得去问度娘。

 

posted @ 2016-09-12 16:48  MrRisingSun  阅读(1007)  评论(0编辑  收藏  举报