美文网首页
iOS hitTest事件传递及其场景应用

iOS hitTest事件传递及其场景应用

作者: 熟睡的毛毛虫 | 来源:发表于2018-09-14 18:05 被阅读28次

    前言

    用过手机吗?了解app吗?作为新时代的社会主义接班人,你知道的。每天用手机,那你知道点击一下屏幕,手机是怎么做出反应的吗?点击某个地方手机就做出了对应的操作反应,接下来我来做一波解释吧。

    正文

    一、 响应者对象

    1. 继承于 UIResponder 的UIApplication、UIWindow、UIView都是响应者对象。
    2. UIResponder四个方法来处理事件。
    UIResponder内部提供了以下方法来处理事件触摸事件
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
    

    touches简单介绍:每个触摸到屏幕的手指都会生成一个touch,touch里面的信息包含了window(当前触发手指所在的window)、view(当前触发手指所在的view)、tapcount(手指数)、timestamp(点击的时间)、phase(当前事件所处的状态)

    二、事件的分发

    产生: 点击屏幕后->系统会将该事件加入到一个UIApplication管理的事件队列中->UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)->主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件,这也是整个事件处理过程的第一步- > 找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理。

    分发:UIApplication->window->寻找处理事件最合适的view
    具体过程:应用如何找到最合适的控件来处理事件?

    1. 首先判断主窗口(keyWindow)自己是否能接受触摸事件
    2. 触摸点是否在自己身上
    3. 从后往前 遍历子控件,重复前面的两个步骤(首先查找数组中最后一个元素)
    4. 如果没有符合条件的子控件,那么就认为自己最合适处理

    找到最合适的view后,就会调用该view的touches方法处理具体的事件。所以,只有找到最合适的view,把事件传递给最合适的view后,才会调用touches方法进行接下来的事件处理。找不到最合适的view,就不会调用touches方法进行事件处理。
    注意:之所以会采取从后往前遍历子控件的方式寻找最合适的view只是为了做一些循环优化。因为相比较之下,后添加的view在上面,降低循环次数。

    三、事件的响应

    找到最合适的view后:

    1. 首先看initial view能否处理这个事件,如果不能则会将事件传递给其上级视图(inital view的superView);
    2. 如果上级视图仍然无法处理则会继续往上传递;
    3. 一直传递到视图控制器view controller,首先判断视图控制器的根视图view是否能处理此事件;
    4. 如果不能则接着判断该视图控制器能否处理此事件,如果还是不能则继续向上传 递;(对于第二个图视图控制器本身还在另一个视图控制器中,则继续交给父视图控制器的根视图,如果根视图不能处理则交给父视图控制器处理);
    5. 一直到 window,如果window还是不能处理此事件则继续交给application处理,如果最后application还是不能处理此事件则将其丢弃。

    四、事件分发过程中的寻找最合适view的时候的几个方法

    1. hitTest:withEvent
      作用:复写这个方法时,对其返回对象进行判断拦截可以修改系统执行响应事件的规律;
      使用注意事项:除非是viewcontroller的view可以在controller里面复写这个方法,其他的view需要进行子类化操作;尽量把判断怼到父视图里进行。

    代码如下:

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
        UIView *view = [super hitTest:point withEvent:event];
        //如果A等于self,就是当前视图响应;
       // 如果A等于view,就是view来响应;
       //如果A等于nil,就是当前视图及其子视图都不响应,最适合的view就是父视图
        return A;
    }
    
    1. viewA pointInside:pointB withEvent:event
      作用:判断pointB点在不在viewA上,返回yes在,no不在;
      还能用来加大点击的作用范围。

    2. pointD = [ viewA convertPoint:pointC toView:viewB ];
      作用:把相对于viewA的pointC点转化到viewB上得到坐标pointD

    五、 影响接收触摸事件的三个因素:

    1. 不允许交互:userInteractionEnabled = NO
    2. 隐藏:如果把父控件隐藏,那么子控件也会隐藏,隐藏的控件不能接受事件
    3. 透明度:如果设置一个控件的透明度<0.01,会直接影响子控件的透明度。alpha:0.0~0.01为透明。

    结束语:

    我所有的自负都来自我的自卑,所有的英雄气概都来自于我内心的软弱,所有的振振有词都因为心中满是怀疑。我假装无情,其实是痛恨自己的深情。我以为人生的意义在于四处游荡流亡,其实只是掩饰至今没有找到愿意驻足的地方。


    我假装无情.png

    本文参考来源

    相关文章

      网友评论

          本文标题:iOS hitTest事件传递及其场景应用

          本文链接:https://www.haomeiwen.com/subject/jnaqgftx.html