Android事件分发机制

本文由本人原创,转载请注明作者

Android中的事件分发机制是新手学习的一个重难点。而且往往学习了之后以为掌握的差不多了,但遇到新问题的时候又发现没有掌握到位或者又忘掉了。笔者就是这种情况,因此将自己已掌握的事件分发机制记录下来,作为记录和交流。

一、背景目的

  • 什么是Android事件分发机制?

事件分发机制是处理Android各种滑动冲突的理论基础,也是学习Android的核心知识点,掌握好View和ViewGroup的事件分发机制是十分重要的。

  • 为什么Android要设计一套事件分发机制?

当父控件和子控件都可以响应用户输入作出行为的时候(比如触摸滑动),这时候就会造成事件冲突。如何判断用户的输入事件由父控件处理还是子控件处理,就需要设计出一套规则了,这套规则就是Android事件分发机制。

  • 没有子父关系的控件会出现事件冲突吗?

没有子父关系的控件,它们是不会产生事件冲突的。因此在处理事件冲突的时候,首先要分析产生冲突的子控件是哪一个,父控件是哪一个。

二、基础知识

  • View和ViewGroup

Android中的控件大致可以分为两类,分别是View和ViewGroup。其中ViewGroup实际上也是继承自View。ViewGroup表示可以拥有子控件的控件,常见的有LinearLayout、ListView这些。后面我们将通过学习知道,在Android事件分发机制中,View是没有拦截方法的,而ViewGroup的拦截方法没有重写的话默认也是不进行拦截的。

  • MotionEvent分类

Android设备可以接收的事件总类很多,比如按压、拖拽、滑动,这些事件分类是由android底层完成的。总的来说,用户操作可以分为三类,及MotionEvent中的ACTION_DOWN(按下),ACTION_MOVE(移动),ACTION_UP(抬起)。从用户手指按下到抬起这一连串的事件被称之为一个事件序列。关于事件序列,下面也会说到。

三、事件分发流程

Android事件分发机制_第1张图片
图片来自网络

从这张图片来看一次点击事件的传递。在这张图中有三个存在子父View关系的View,其中上面两个能作为父View的自然是属于ViewGroup了。

ViewGroup—dispatchTouchEvent方法

Touch事件发生后,顶级父View先接受到消息,此时会先调用顶级View的dispatchTouchEvent方法,这在图片上没有画出来。该方法的返回true的话,代表事件被消费掉了(当事件被消费时便不再传递);返回false的话事件不再往下传递,由上一级View的onTouchEvent方法来处理。如果没有重写该方法的话(即调用ViewGroup中的dispatchTouchEvent方法),会判断onInterceptTouchEvent的返回值来确定下一步传递方向。

ViewGroup—onInterceptTouchEvent方法

该方法顾名思义,判断当前View是否拦截该事件。如图所示,返回Ture的话会拦截事件传递,调用顶级View的onTouchEvent方法来处理事件。返回false的话表示不中断,事件继续向下传递。传递到下一级父View的过程也是一样,onInterceptTouchEvent方法返回false的话会一直向下传递到子View。

View-dispatchTouchEvent方法

View的dispatchTouchEvent方法跟ViewGroup是有区别的。通过看源码可以知道,View没有onInterceptTouchEvent方法,因此也它会直接调用onTouchEvent方法来判断事件是否被消耗。另外如果View被设置了各种Listener(如OnClickListener)之后,对应的事件也会随着Listener中对应的方法返回true而被消耗。

View—onTouchEvent方法

传递到子View的时候会调用子View的dispatchTouchEvent方法,一般自定义View的时候在onTouchEvent中处理与用户触摸按压的交互逻辑。不管该方法过程如何,如果onTouchEvent的返回值为True表示事件被消耗,事件不再传递。反之,事件将向上传递,传给父View去处理。另外需要注意的是当View的clickable和longClickabale属性同时为false的时候,代表View不可点击(如TextView),因此onTouchEvent方法也会默认返回false不消耗事件。

ViewGroup—onTouchEvent方法

ViewGroup对onTouchEvent的方法和View一样,返回true的话代表事件被消耗,返回false将事件继续向上传递。具体的行为要看具体的重写方法。

四、总结分发流程

可以看到事件传递时是一层层向下传递接受,再由下往上进行处理。这和现实工作也很类似:

产品经理提了一个新的需求,高级程序员接到需求先考虑下要不要自己做(onInterceptTouchEvent方法过程),觉得应该自己处理就自己完成了(ViewGroup—onTouchEvent方法过程);觉得应该由下属去做就下发给见习程序员,见习程序员没有下属只能自己去处理(View—onTouchEvent方法过程);见习程序员如果很好地解决需求了(onTouchEvent方法返回true),这个事件就到此结束了。如果需求太难,见习程序员处理不了这个需求(onTouchEvent方法返回false),那么就会再交给上级去处理。

可见Google的程序员在设计这些代码时的用的方法十分巧妙,也是和现实相结合地去设计代码,对于开发者也便于理解。
任玉刚大神在《Android开发艺术探索》一书中对事件分发机制的讲解十分到位,推荐有兴趣的朋友去看看。书中用一段伪代码把事件分发机制抽象的非常清楚:

public boolean dispatchTouchEvent(MotionEvent event) {
    boolean consume =false;
    if(onInterceptTouchEvent(ev)) {
        consume = onTouchEvent(ev);
    } else {
        consume = child.dispatchTouchEvent(ev);
    }
    return consume;
}

其中comsume代表事件是否被消耗。当事件传递到ViewGroup的时候,先判断是否拦截。拦截的话由自己的onTouchEvent方法处理;不拦截的话,分发给子View处理,调用子View的dispatchTouchEvent方法。

你可能感兴趣的:(Android事件分发机制)