zoukankan      html  css  js  c++  java
  • 事件分发机制

    前言总结

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

  • 相关阅读:
    导出api文档
    Webservice测试从头来
    Java8新特性【转】
    spring获取bean的时候严格区分大小写
    java static 方法使用笔记
    maven Spring获取不到配置文件
    4月22日
    4月21日
    9月20日
    9月18日
  • 原文地址:https://www.cnblogs.com/zhangxiaoxu/p/5777331.html
Copyright © 2011-2022 走看看