也谈Android事件分发
说到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如何传递?
看看流程图就明白了。
最后附事件分发流程图:
事件分发流程图其实还有一些特殊情况,比如说事件丢弃,以后再加以说明。