对象
- Activity
- View
- ViewGroup
内容
- dispatchTouchEvent()
- onInterceptTouchEvent()
- onTouchEvent()
在Android 中,视图的概念其实就是View,存放由多个View组成的视图组的载体就是ViewGroup,最后把视图或者视图组的呈现给使用者的载体,就是大家所熟悉的Activity。然而在当下触屏的电子产品时代,对于一个Android开发者而言,触碰事件的基础也将不在仅仅是基础了。
- dispatchTouchEvent:处理触碰事件的分发,执行super.dispatchTouchEvent(ev),事件向下分发。
- onInterceptTouchEvent:ViewGroup提供的方法,默认返回false,返回true表示拦截。
- onTouchEvent:默认返回true,表示消费了这个事件。
Activity里,有两个回调函数
public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onTouchEvent(MotionEvent event);
View里,有两个回调函数
public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onTouchEvent(MotionEvent event);
ViewGroup里,有三个回调函数
public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onInterceptTouchEvent(MotionEvent ev);
public boolean onTouchEvent(MotionEvent event);
Activity
Android中通常点击事件用MotionEvent来表示,当一个点击操作发生时,事件最先传递给当前的Activity,由Activity的dispatchTouchEvent来进行事件的分发,具体工作是由Activity内部的Window来完成的。Window会将事件传递给decorview,decorview一般就是当前界面的底层容器(即setContentView所设置的View的父容器),通过Activity.getWindow.getDecorView()可以获得。关于Activity事件分发机制的源码,我们重点来看下dispatchTouchEvent和onTouchEvent方法。
dispatchTouchEvent
实现类Activity的dispatchTouchEvent方法,用来做Log信息跟踪:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
String motionEventInfo = "";
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
motionEventInfo = "ACTION_DOWN";
break;
case MotionEvent.ACTION_MOVE:
motionEventInfo = "ACTION_MOVE";
break;
case MotionEvent.ACTION_UP:
motionEventInfo = "ACTION_UP";
break;
default:
motionEventInfo = ev.getAction() + "";
break;
}
Log.d(GlobalUtils.TAG, "[MainActivity] dispatchTouchEvent : motionEventInfo = " + motionEventInfo);
//事件一开始就由Activity所附属的Window进行分发,
//如果返回true,整个事件循环就结束了,不在走onTouchEvent流程,
//如果返回false意味着事件没人处理,所有事件往下分发给onTouchEvent来处理,
//如果最后所有View的onTouchEvent都返回了false,那么Activity就要来做最后的收场。
boolean isSuperDispatchTouchEvent = getWindow().superDispatchTouchEvent(ev);
Log.e(GlobalUtils.TAG, "[MainActivity] dispatchTouchEvent : Window.SuperDispatchTouchEvent = " + isSuperDispatchTouchEvent);
boolean isNext = super.dispatchTouchEvent(ev);
Log.d(GlobalUtils.TAG, "[MainActivity] dispatchTouchEvent : isNext = " + isNext);
return true;
}
基类Activity的dispatchTouchEvent的源码:
/**
* 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();
}
//事件一开始就由Activity所附属的Window进行分发,
//如果返回true,整个事件循环就结束了,不在走onTouchEvent流程,
//如果返回false意味着事件没人处理,所有事件往下分发给onTouchEvent来处理,
//如果最后所有View的onTouchEvent都返回了false,那么Activity就要来做最后的收场。
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
//分发给onTouchEvent处理,
return onTouchEvent(ev);
}
boolean isSuperDispatchTouchEvent = getWindow().superDispatchTouchEvent(ev)是boolean isNext = super.dispatchTouchEvent(ev)中的内容:
1、事件一开始就由Activity所附属的Window进行分发
2、如果isSuperDispatchTouchEvent 值为true,那么就super.dispatchTouchEvent(ev)就直接return true不在往下执行onTouchEvent事件,意味着事件的结束
3、如果isSuperDispatchTouchEvent 值为false,那么事件就会往下被分发到onTouchEvent中处理
4、Activity的onTouchEvent是最后来消化其他子View没有处理的touch事件
onTouchEvent
实现类的onTouchEvent方法,用来做Log信息跟踪:
@Override
public boolean onTouchEvent(MotionEvent event) {
String motionEventInfo = "";
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
motionEventInfo = "ACTION_DOWN";
break;
case MotionEvent.ACTION_MOVE:
motionEventInfo = "ACTION_MOVE";
break;
case MotionEvent.ACTION_UP:
motionEventInfo = "ACTION_UP";
break;
default:
motionEventInfo = event.getAction() + "";
break;
}
Log.d(GlobalUtils.TAG, "[MainActivity] dispatchTouchEvent : onTouchEvent = " + motionEventInfo);
//目前还不清楚mWindow.shouldCloseOnTouch(this, event)的具体源码
boolean isNext = super.onTouchEvent(event);
Log.d(GlobalUtils.TAG, "[MainActivity] onTouchEvent : isNext = " + isNext);
return isNext;
}
基类Activity的onTouchEvent的源码:
/**
* Called when a touch screen event was not handled by any of the views
* under it. This is most useful to process touch events that happen
* outside of your window bounds, where there is no view to receive it.
*
* @param event The touch screen event being processed.
*
* @return Return true if you have consumed the event, false if you haven't.
* The default implementation always returns false.
*/
public boolean onTouchEvent(MotionEvent event) {
if (mWindow.shouldCloseOnTouch(this, event)) {
finish();
return true;
}
return false;
}
Activity的onTouchEvent算是Android 应用层上最后用来消化点击事件的最后防线了,然而对于super.onTouchEvent(event)中的mWindow.shouldCloseOnTouch(this, event)事件,目前还不清楚具体的作用,因为目前跟踪不到其内部源码。
总结:
Log信息如下:
04-04 21:23:15.307 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : motionEventInfo = ACTION_DOWN
04-04 21:23:15.307 12682-12682/com.sdf.aso.viewlifecycle E/dfsu: [MainActivity] dispatchTouchEvent : Window.SuperDispatchTouchEvent = false
04-04 21:23:15.307 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : onTouchEvent = ACTION_DOWN
04-04 21:23:15.307 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] onTouchEvent : isNext = false
04-04 21:23:15.307 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : isNext = false
04-04 21:23:15.367 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : motionEventInfo = ACTION_UP
04-04 21:23:15.367 12682-12682/com.sdf.aso.viewlifecycle E/dfsu: [MainActivity] dispatchTouchEvent : Window.SuperDispatchTouchEvent = false
04-04 21:23:15.367 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : onTouchEvent = ACTION_UP
04-04 21:23:15.367 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] onTouchEvent : isNext = false
04-04 21:23:15.367 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : isNext = false