也谈Android事件分发

作者: 东风四幺 | 来源:发表于2016-05-28 23:12 被阅读340次

    说到Android事件分发,想必大家都做了不少研究,读了不少博客文章。 今天抛出一块砖,也来谈谈自己对Android事件分发的理解。

    其实也谈不上多么理解,在总结前人的一些博客的基础上,自己做了验证,用自己的话来描述出来,争取用最简单的话语把事件分发的逻辑表达清楚,正确。


    回到正题。

    事件怎么来?怎么去?

    我们知道Android上的事件都是发生在View或者ViewGroup(继承于View)上并在上面进行传递的。

    有几个关键的函数大家应该都知道了。

    对View来说,那就是:

    负责事件分发的:

    public boolean dispatchTouchEvent(MotionEvent event)

    负责事件处理的:

    public boolean onTouchEvent(MotionEvent event)

    对ViewGroup来说,那就是:

    负责事件分发的:

    public boolean dispatchTouchEvent(MotionEvent event)

    负责事件拦截的:

    public boolean onInterceptTouchEvent(MotionEvent ev)

    负责事件处理的:

    public boolean onTouchEvent(MotionEvent event)

    还有重要的一点, 事件的根儿呢? 用户点击屏幕的各种事件(ACTION_DOWN,ACTION_MOVE,ACTION_UP等),一开始其实是由Activity来负责往下分发的, 所以Activity也有两个重要的函数,他们是:

    负责事件分发的:

    public boolean dispatchTouchEvent(MotionEvent event)

    负责事件处理的:

    public boolean onTouchEvent(MotionEvent event)

    通过阅读Activity的dispatchTouchEvent方法代码,通过分析线程调用堆栈发现,最终会调用到decorView的dispatchTouchEvent方法,我们知道decorView继承自FrameLayout,也就是会调用到ViewGroup的dispatchTouchEvent方法。

    即:事件从

    Activity的dispatchTouchEvent  ---->  ViewGroup的dispatchTouchEvent

    我们知道,所有的屏幕操作事件都是以按下(ACTION_DOWN)为前提的,接下来才会有ACTION_MOVE和ACTION_UP。

    我们先来看ACTION_DOWN事件的传递:

    从上面可以得知,事件传递到ViewGroup的dispatchTouchEvent之后,如何处理呢? 会调用到ViewGroup的onInterceptTouchEvent判断ViewGroup是否对事件进行拦截,如果返回true,就是要拦截,自己去处理;如果返回false(默认返回false), 就是不进行拦截,继续往下分发。

    但是,每个事件传递都会调用ViewGroup的onInterceptTouchEvent吗? 不一定!!!

    这就好像复杂了点, 其实说来也简单:只有当前事件是ACTION_DOWN或者上一次事件被ViewGroup底下的某个子View消费了的时候,才会调用ViewGroup的onInterceptTouchEvent.

    接着刚才继续说,如果ViewGroup拦截了事件,就会调用ViewGroup的onTouchEvent方法去处理了,结果怎么样呢? 如果返回true,代表ViewGroup自己把事件给消费了,ACTION_DOWN事件就结束了。后面的事件怎么传递呢?不说了,看最后的流程图吧。 如果返回false, 代表ViewGroup自己没有把事件消费,(这就有点耍流氓了,把事件拦截了又不消费,你想干嘛? )主子Activity看不顺眼了,于是事件又回到了Activity, 让Activity的onTouchEvent去处理了。还有更严重的呢!好你个ViewGroup,ACTION_DOWN事件你不想处理,那其他事件也用不着你管了!(一边凉快去吧~),所以,后面的事件都是Activity分发给自己的onTouchEvent去处理了。

    那如果ViewGroup没有拦截ACTION_DOWN呢?ViewGroup说,孩子们,这个活儿你们看着办吧!于是事件就分发给了子View, 子view调用dispatchTouchEvent方法,子View如果按照祖宗的规矩处理的话,就会调用onTouchEvent方法去处理,处理结果呢? 如果直接返回true,  就代表子View把事件消费了,ACTION_DOWN到此结束。下一步的事件还是会传递进来。 如果直接返回false, 就代表子View没消费事件,怎么办? 回传给ViewGroup的onTouchEvent去处理,如果ViewGroup的onTouchEvent消费了ACTION_DOWN事件(即返回true),那后面的事件(ACTION_MOVE,ACTION_UP)就简单了,会直接派发给ViewGroup去处理,没孩子的事儿了! 那如果ViewGroup也没有消费ACTION_DOWN事件(即onTouchEvent返回false), 那只能主人Activity自己去处理了,回传给Activity的onTouchEvent处理,并且后面的事件也是Activity自己去处理了,奴才们都一边玩蛋去吧!

    ACTION_MOVE,ACTION_UP如何传递?

    看看流程图就明白了。

    最后附事件分发流程图:

    事件分发流程图

    其实还有一些特殊情况,比如说事件丢弃,以后再加以说明。

    相关文章

      网友评论

      • 岛在深海处:厉害,希望以后多发点这种详细的文章
      • 大河儿马:很清晰
      • Tang1024:文章写的好,流程图配的更好
      • 浮生如茶2016:讲的真不错,如果能加点实例的话就更不错了!
        东风四幺:@浮生如茶2016 谢谢。我也是写实例测试很久,费了两三个小时敲出来的这篇文章。等我有时间我再把实例加上,还有事件丢弃那部分。

      本文标题:也谈Android事件分发

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