前言:
一般我们处理事件,都是针对某一个View来处理了,要么是添加onTouchListener监听器,要么继承View然后重写View#onTouchEvent,
甚至不用重写,只要使用Widget自己的监听函数 ,或者GestureDetector就OK了.
但是理解Android事件模型,对于理解GestureDetector,及Android事件的交互,写出具有出色的交互的应用.
都是必经之路.
一:ViewGroup与View的事件模型
我们都知道Android界面实际是一棵View的树.枝干是ViewGroup.
ViewGroup继承自View,但是又是管理View的容器.那么ViewGroup与View的事件关系是怎么样的呢?
这需要从另一个重要的ViewGroup中的方法,如下说起:
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
它的默认实现很简单,就是把事件交给子View去处理.自己不拦截.
Intercept就是拦截的意思.
此方法的注释,对于ViewGroup与View的事件模型说得很清楚,
主要是以下几点:
(1) 如果此方法返回false,说明此ViewGroup暂时(只是暂时)对于触控事件不感兴趣.
但是不知道后面的事件它感不感兴趣.所以后续事件还会一直传递到此方法中来,供此方法判断.
(2) 如果此方法返回true了.那么说明此方法对应的ViewGroup开始对于此事件(或者手势)感兴趣了.
那么后续事件就会直接给此方法对应的ViewGroup的onTouchEvent方法来处理事件了.
(3) 如果此方法一开始返回false,说不感兴趣这个时候事件发给了目录View.
现在又返回true,说感兴趣了.那么目录View就会收到一个action为ACTION_CANCEL的事件.
跟此方法返回true时的事件是同一个事件 ,只是action变了.
(4) ViewGroup会在这里接收触控开始的事件.
规则就是上面这些 ,那么是谁在后面处理这些规则呢?
就是ViewGroup.它在disptachTouchEvent方法中,进行了一系列的处理来实现这种模型.
public boolean dispatchTouchEvent(MotionEvent ev)
对于单独的View本身来说,它也有一个简单的事件派发模型.通过以下代码就可以很明白的看出来了:
View#dispatchTouchEvent(MotionEvent event):
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
return true;
}
if (onTouchEvent(event)) {
return true;
}
二: Activity与View的事件模型
事件先到Activity中,然后Activity调用:
/**
* Called to process touch screen events. You can override this to
* intercept all touch screen events before they are dispatched to the
* window. Be sure to call this implementation for touch screen events
* that should be handled normally.
*
* @param ev The touch screen event.
*
* @return boolean Return true if this event was consumed.
*/
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
来分发事件, 这里的逻辑是:
先让用户界面窗口处理:getWindow().superDispatchTouchEvent(ev)
如果窗口没有处理这个事件.
那就交给Activity自己处理.return onTouchEvent(ev)
这个Window跟View层级是怎么交互的呢?
我们找到了Window的实现类:PhoneWindow(com.android.internal.policy.impl.PhoneWindow)
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
这个mDecor就是用户界面的根View了.
private final class DecorView extends FrameLayout
(com.android.internal.policy.impl.PhoneWindow.DecorView)
原来窗口将事件交给根View来进行事件派发的.
mDecor调用自己的superDispatchTouchEvent(event)
然后将事件派发的任务交给了自己的dispatchTouchEvent
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
这里调用的super.dispatchTouchEvent 就是ViewGroup的声明的dispatchTouchEvent的了.