美文网首页
5、事件冲突相关

5、事件冲突相关

作者: XX杰 | 来源:发表于2022-10-16 22:09 被阅读0次

    1、常用事件~如图


    WX20221011-235812.png
    事件可以走的流程 down up。    down move up。  down cancle。down move cancle
    

    2、可以进行 事件 分发和拦截的只有 viewGroup 事件的处理只能在 view 里面

    a、在 ViewGroup 的 dispatchTouchEvent 中先走   onInterceptTouchEvent  判断是否需要拦截
      1、不拦截的话 会通过 dispatchTransformedTouchEvent 调用 子 view的  dispatchTouchEvent方法, 然后看 b 的处理逻辑
      2、拦截的话,会走 父类的 dispatchTouchEvent (也就是 他自己的 dispatchTouchEvent)
    b、在view中的 dispatchTouchEvent 
      1、如果设置了OnTouchListener,会先走 OnTouchListener 的 onTouch 方法
          如果 OnTouchListener 返回 true, 则 onTouchEvent 就不会执行,里面的 onClick 就不会执行了
          如果返回false,则会走 view 本身的 onTouchEvent ,在UP 的时候会走performClickInternal 然后走 onClick 事件
    

    3、上面主要阐述了 事件的 处理 逻辑 ,下面介绍一下分发的逻辑

    a、如果 子 view 有 OnTouchListener 或者 onClick 事件,则 view 的 dispatchTouchEvent 一定返回 true 
        这里返回 true 表示 告诉  父类  控件 这个事件 我已经消费了
    b、在 ViewGroup 的 dispatchTouchEvent 事件中 是在 down 事件 调用 onInterceptTouchEvent 并获取返回值的
         1、 如果拦截了 ,mFirstTouchTarget 这个就是 null ,然后才会 执行 方法 dispatchTransformedTouchEvent
          其中 dispatchTransformedTouchEvent 传入的 child 参数是 null ,所以在 该方法里面 会 调用 super.dispatchTouchEvent() ,  
          就走到了 view 的dispatchTouchEvent() , 然后的处理逻辑跟 2 一样 <ViewGroup 也是 extends View>
        2、如果没有拦截, onInterceptTouchEvent 返回的是 false  并且 是 down 事件 我们走分发流
    

    同上 分发 流程

    1、将 ViewGroup 中的 所有子 view 做一个排序 根据 子view 的 z 值 。在方法 buildTouchDispatchChildList 中的 buildOrderedChildList 方法里面 如果没有 z 值,是根据 xml 中的顺序 排列的
    2、对 排序 之后的 view 的集合 进行一个 for 的遍历, 源码中是 倒序 遍历的
    对每一个 view 的操作 如下:
    a、先对view 进行一个判断, view是否可见或者是否执行了animation 和 点击的point 是否在view的范围内
    b、如果 a 中的 判断不成立, 则执行 continue 。获取 下一个 子 view

    c、a 中的判断成立:执行下面的 三个流程
    i、调用 dispatchTransformedTouchEvent 方法 第三个参数是 当前的 view。所以会 执行 子 view 的dispatchTouchEvent 方法,分发出去了
    ii、如果 子 view 的dispatchTouchEvent 返回 false, 则 循环继续走,直到循环 走完之后,走

    自己本身处理 和 拦截的流程 一样 
    if (mFirstTouchTarget == null) {
                    // No touch targets so treat this as an ordinary view.
                    handled = dispatchTransformedTouchEvent(ev, canceled, null,
                            TouchTarget.ALL_POINTER_IDS);
     } else {
    // Dispatch to touch targets
    }
    

    iii、如果 子 view 的dispatchTouchEvent 返回 true ,则说明 子view 把事件处理了这个时候
    进入到 if 里面 执行 addTouchTarget 方法,给 newTouchTarget 赋值 此时:

    • mFirstTouchTarget = newTouchTarget 并且 newTouchTarget.next = null 同时 alreadyDispatchedToNewTouchTarget = true;
    newTouchTarget = addTouchTarget(child, idBitsToAssign);
    alreadyDispatchedToNewTouchTarget = true;
    break;  跳出循环
    

    iv、此时因为 mFirstTouchTarget 不是 null 了所以会走 else 逻辑
    这里有一个 while 循环。来处理 单点触摸 和 多点触摸 这个时候 viewGroup 的 dispatchTouchEvent 返回true。

    因为 MOVE 事件 是不会 走 循环的,并且move 事件来的时候 mFirstTouchTarget 不是 null
    所以move 事件会直接走 上面的 else 代码块,然后又会 走到 dispatchTransformedTouchEvent 方法

    这是 dispatchTouchEvent 中的 拦截的代码
    if (actionMasked == MotionEvent.ACTION_DOWN
                        || mFirstTouchTarget != null) {
                    final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                    if (!disallowIntercept) {   可以设置  disallowIntercept 为 true ,是 拦截方法失效
                        intercepted = onInterceptTouchEvent(ev);
                        ev.setAction(action); // restore action in case it was changed
                    } else {
                        intercepted = false;
                    }
                } else {
                    // There are no touch targets and this action is not an initial down
                    // so this view group continues to intercept touches.
                    intercepted = true;
                }
    通过 方法 requestDisallowInterceptTouchEvent() 可以设置 viewgroup 是否强制 不拦截
    

    相关文章

      网友评论

          本文标题:5、事件冲突相关

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