5、事件冲突相关

2022-10-16  本文已影响0人  XX杰

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 赋值 此时:

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 是否强制 不拦截
上一篇下一篇

猜你喜欢

热点阅读