對象
- 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