android的进阶Android技术知识Android知识

窥探Android Touch事件内幕系列之二

2016-09-28  本文已影响304人  桃子妈咪

上一篇文章我们主要介绍了Android UI事件处理机制-基于监听器方式、基于回调方法,同时从View的角度分析了Touch事件分发流程。这一篇文章我们将从ViewGroup角度来分析Touch事件分发流程,之前计划的关于Robolectric如何测试相关事件分发流程将会在后续『单元测试之-自定义View』中进行介绍。

事件传递流程

Touch事件在Android中对应的就是MotionEvent类。对Touch事件的分发其实就是对MotionEvent对象进行分发。当我们在屏幕上进行一次点击操作时,MotionEvent就产生了,Android系统会将这个MotionEvent对象传递到一个具体的View进行处理,这个传递过程就是事件分发。Android事件分发是一种委托思想:上层委托下层,父容器委托子元素处理。

下图是Android系统的界面结构图:最顶层为Activity的ViewGroup,下面有若干的ViewGroup节点,每个节点之下又有若干的ViewGroup节点或者View节点,依次类推。当一个Touch事件到达根节点,即Acitivty的ViewGroup时,该Touch事件会被依次分发,分发过程就是调用子View(ViewGroup)的dispatchTouchEvent方法实现的。简单来说,就是ViewGroup遍历它包含着的子View,调用每个View的dispatchTouchEvent方法,而当子View为ViewGroup时,又会通过调用ViwGroup的dispatchTouchEvent方法继续调用其内部的View的dispatchTouchEvent方法。下图中Touch事件下发顺序是这样的:①-②-⑤-⑥-⑦-③-④。dispatchTouchEvent方法只负责事件的分发,它拥有boolean类型的返回值,当返回为true时,顺序下发会中断。在上述例子中如果⑤的dispatchTouchEvent返回结果为true,那么⑥-⑦-③-④将都接收不到本次Touch事件。(这段节选自:Android:30分钟弄明白Touch事件分发机制

Android View结构模型

ViewGroup继承自View,ViewGroup中对触摸事件的处理,很多也都继承于View。但是,ViewGroup又有自己对触摸事件的特定处理。ViewGroup重载了dispatchTouchEvent()方法,新增了onInterceptTouchEvent()方法。上一篇文章中我们已经分析过View类的事件处理机制-dispatchTouchEvent、onTouchEvent,本篇将会分析ViewGroup的dispatchTouchEvent分发流程。

ViewGroup->dispatchTouchEvent流程

关于ViewGroup->dispatchTouchEvent已经有很多大神们进行了详细的源码分析,我这里给出一些链接,方便大家去参考

1、Android 触摸事件机制(四) ViewGroup中触摸事件详解

2、 13.View的事件分发机制——dispatchTouchEvent详解

3、Android ViewGroup事件分发机制

为节约篇幅这篇文章就不贴源码了,将以精心烹制的『流程图』作为�主菜,另配上香甜可口的甜点『解析』为大家呈现ViewGroup中dispatchTouchEvent这道饕餮盛宴。

ViewGroup->dispatchTouchEvent整体流程图

流程图中涉及到的拦截机制、TouchTarget、MotionEvent、Down操作分发流程等等,会在下面的内容中为大家一一讲解。

拦截机制

在自定义ViewGroup中,有时候需要实现Touch事件拦截,比如ListView下拉刷新就是典型的Touch事件拦截的例子。Touch事件拦截就是在Touch事件被父 view拦截,不会分发给其child,即使触摸发生在该child身上。被拦截的事件会转到parent view的onTouchEvent方法中进行处理。

那么ViewGroup的拦截机制具体原则是什么呢?我们先来看下流程图,方便大家理解。

ViewGroup->dispatchTouchEvent->拦截机制流程图.png

这里根据流程图总结下具体原则:

TouchTarget

TouchTarget是ViewGroup的一个内部类,是一个触摸对象的链表类。ViewGroup类中mFirstTouchTarget就是当前ViewGroup中触摸对象链表的头节点,用于记录处理某Down操作的所有子View和触摸点(对于多点触摸,需要记录每次的触摸点)信息。下面给出了这个类的源码,方便大家理解。

 /* Describes a touched view and the ids of the pointers that it has captured.
     *
     * This code assumes that pointer ids are always in the range 0..31 such that
     * it can use a bitfield to track which pointer ids are present.
     * As it happens, the lower layers of the input dispatch pipeline also use the
     * same trick so the assumption should be safe here...
     */
    private static final class TouchTarget {
        private static final int MAX_RECYCLED = 32;
        private static final Object sRecycleLock = new Object[0];
        private static TouchTarget sRecycleBin;
        private static int sRecycledCount;

        public static final int ALL_POINTER_IDS = -1; // all ones

        // The touched child view.
        public View child;

        // The combined bit mask of pointer ids for all pointers captured by the target.
        public int pointerIdBits;

        // The next target in the target list.
        public TouchTarget next;

        private TouchTarget() {
        }

        public static TouchTarget obtain(View child, int pointerIdBits) {
            final TouchTarget target;
            synchronized (sRecycleLock) {
                if (sRecycleBin == null) {
                    target = new TouchTarget();
                } else {
                    target = sRecycleBin;
                    sRecycleBin = target.next;
                     sRecycledCount--;
                    target.next = null;
                }
            }
            target.child = child;
            target.pointerIdBits = pointerIdBits;
            return target;
        }

        public void recycle() {
            synchronized (sRecycleLock) {
                if (sRecycledCount < MAX_RECYCLED) {
                    next = sRecycleBin;
                    sRecycleBin = this;
                    sRecycledCount += 1;
                } else {
                    next = null;
                }
                child = null;
            }
        }
    }

MotionEvent

这篇文章一开始就介绍了MotionEvent是事件源(Button、CheckBox、EditText等)产生的Touch事件。我们需要从MotionEvent中获取哪些信息呢?

Down操作处理流程

当Touch事件MotionEvent中的ACTION_DOWN、ACTION_POINTER_DOWN操作来临时ViewGroup的分发流程是如何的呢?请先看流程图,我们再来分析。

ViewGroup->dispatchTouchEvent->Down操作处理流程.png

Up、Move操作处理流程

ViewGroup主要是先通过对Down操作进行分发,记录处理Down操作的子View链表,然后循环遍历该链表,完成Up、Move操作的分发处理。

ViewGroup->dispatchTouchEvent->Up/Move操作处理流程

总结

上一篇 下一篇

猜你喜欢

热点阅读