美文网首页Android自定义ViewAndroid开发Android开发经验谈
Android事件分发机制(二)——ViewGroup的事件分发

Android事件分发机制(二)——ViewGroup的事件分发

作者: 程序员丶星霖 | 来源:发表于2019-12-12 14:11 被阅读0次

    一、ViewGroup事件分发的流程图

    ViewGroup事件分发.png

    以上是ViewGroup事件分发的整体流程,其中主要的方法有:

    • dispatchTouchEvent(MotionEvent ev)
    • onInterceptTouchEvent(MotionEvent ev)
    • onTouchEvent(MotionEvent ev)

    二、ViewGroup事件分发源码解析

    ViewGroup的dispatchTouchEvent方法主要做了以下三件事:

    1. 去判断是否需要拦截事件
    2. 在当前ViewGroup中找到用户真正点击的View
    3. 分发事件到View上

    在ViewGroup的dispatchTouchEvent(ev)中有4个if判断:

    ViewGroup01.png

    首先是一个调试对象的判定,mInputEventConsistencyVerifier是在ViewGroup的父类(View)中进行实例化的。

    ViewGroup03.png ViewGroup02.png

    其中事件分发的主要流程在onFilterTouchEventForSecurity(ev)这个判断中。

    ViewGroup05.png

    接下里进去看一下onFilterTouchEventForSecurity(ev)方法,此方法主要用于判定触摸事件是否符合安全策略,如果此方法返回true(即符合安全策略),则继续事件分发,否则dispatchTouchEvent(ev)方法将返回false,事件未被消费,整个流程结束:

    安全策略源码.png

    符合安全策略的话就会继续走下面分发的逻辑,系统判断当前的事件是否为ACTION_DOWN,如果当前为ACTION_DOWN事件,则执行如图两个方法,通过cancelAndClearTouchTargets(ev)方法来取消并且清除触摸事件的目标列表,通过resetTouchState()方法来重置所有的触摸状态,为新的事件循环作准备:

    判断当前是否为ACTION_DOWN.png

    接下来系统会检查拦截情况:

    判断是否拦截事件.png

    当intercepted为true,表示拦截事件,不会继续分发;返回false,表示不会拦截事件,继续分发。

    onInterceptTouchEvent方法源码.png

    onInterceptTouchEvent()的判断条件:如果当前事件来自鼠标事件输入,当前事件为ACTION_DOWN事件,当前是否按下了鼠标左键并且当前触摸点是在一个滚动条上,此时才会返回为true,否则就会返回false。

    接下来就会进入事件派发的逻辑:

    事件派发过程.png

    如果当前不是取消时间,并且不去拦截这个事件,那就就进行事件分发的逻辑中;

    在事件分发逻辑中,首先会清空掉所有之前的触摸点的信息,然后获取到当前ViewGroup下所有子View的数量,如果newTouchTarget为空,并且子View的数量不为0的情况下,就会进入下面的逻辑中;

    首先获取到当前触摸点的坐标值;获取到所有可以被分发的子View的集合;customOrder用于判断是否自定义了绘制顺序,接下来循环遍历子View的集合,通过getAndVerifyPreorderedIndex(childrenCount,i,customOrder)方法来获取到子View的索引值。

    getAndVerifyPreorderedIndex源码.png

    获取到子View索引值后,再通过getAndVerifyPreorderedView方法获取到View。

    getAndVerifyPreorderedView的源码.png

    现在为止,目标View就已经获取到了。接下来是对当前的View进行处理。

    通过canViewReceivePointerEvents()方法和isTransformedTouchPointInView()来判断当前的View是否是处理该事件的View。

    canViewReceivePointerEvents()用于检查当前的目标View是否可以接受到触摸事件;isTransformedTouchPointInView()判断当前触摸事件是否在View 的范围内。

    判断当前的View是否是处理该事件的View.png

    在获取到View 之后,就去获取其触摸对象。

    获取触摸对象.png

    如果当前触摸对象newTouchTarget不为null,表示当前的子View已经获取到一个触摸事件了,就直接结束当前的循环。
    如果当前触摸对象newTouchTarget为null,就会调用resetCancelNextUpFlag(child)方法,此方法用于检查传入的View是否设置了暂时不会接受事件的标识,如果有就清除掉标识。

    接下来,系统就会进行下一层的事件分发。

    ViewGroup过度到View中.png

    dispatchTransformedTouchEvent()方法描述了事件从ViewGroup到View是怎样过度的。

    dispatchTransformedTouchEvent第一部分.png dispatchTransformedTouchEvent第二部分.png

    如果dispatchTransformedTouchEvent()返回为true的话,说明事件在子View中已经被消费了,当前ViewGroup就会结束掉循环。

    到此为止,ViewGroup对子View查找过程就结束了。在查找完之后,会把子View的集合preorederedList清除掉。

    循环遍历结束.png 分发触摸事件.png

    接下来系统会判断mFirstTouchTarget是否为null,如果它恒等为null的话,表示到此为止依然没有子View来处理触摸事件。不为null的话,系统就会遍历目标列表。

    最后会将handled返回。

    学海无涯苦作舟

    个人博客:http://www.coderlearning.cn/

    我的微信公众号.jpg

    相关文章

      网友评论

        本文标题:Android事件分发机制(二)——ViewGroup的事件分发

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