Android(觸摸屏)中應用程序與用戶交互用的就是touch事件來完成的,一個界面上的控件會有很多,那麼
一個touch事件是如何傳遞的呢?
一、簡介
Android中的touch事件都是以down(按下)事件開始,up(擡起)事件結束的
事件類型有:ACTION_DOWN(按下)、ACTION_UP(擡起)、ACTION_MOVE(移動)
ACTION_POINT_DOWN(多個手指按下)、ACTION_POINT_UP(多個手指擡起)
二、事件分發
Android中的View分爲兩個,一類是ViewGroup(含有子類View);一類是View(沒有子類View),兩類的
事件分發機制有所不同
1.View
有兩個控件TextView和Button,分別點擊一次,並且打印響應的信息(onTouch默認返回爲false)
單擊一次有兩個事件響應:down和up分別執行一次,首先down事件執行如下
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("button");
return false;
}
});
textView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("textView");
return false;
}
});
分別點擊一次後打印出來的效果如下
爲什麼點擊兩個控件最後打印出信息的數量是不同的呢,那我們首先要從TextView和Button的不同
入手,TextView默認是不可點擊的,Button是可以點擊的,然後帶着這兩點不同,看看系統的源碼有
一下重大的發現呢!!
①button和textView都是View的子類,通過setOnTouchListener把OnTouchListener對象傳到View
public boolean dispatchTouchEvent(MotionEvent event) {
....
//mOnTouchListener不爲空,並且當前控件可用,onTouch方法對應得返回值
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
//如果if對於邏輯不成立,調用onTouchEvent
//onTouch先於onTouchEvent,並且覺得當前onTouchEvent是否調用
return onTouchEvent(event);
}
②兩個子View的onTouch返回值都爲false,那麼會執行本View的onTouchEvent(Event);
③View的onTouchEvent()方法執行如下
public boolean onTouchEvent(MotionEvent event) {
....
//判斷當前控件是否有點擊事件,如果有則執行if中邏輯,如果沒有則不執行返回false
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
switch (event.getAction()) {
//點擊事件觸發點
case MotionEvent.ACTION_UP:
...
performClick();
...
}
//此處返回true則說明onTouchEvent,說明dispatchTouchEvent返回true,則響應所有事件
return true;
}
//此處返回false,等同於onTouchEvent,dispatchTouchEvent返回false,不響應所有事件
return false;
}
TextView不可點擊,那麼直接返回false,表示事件沒有被消耗,那麼down事件沒有被消耗,up事
件也不會繼續執行,所以textView只輸出了一次結果
Button可以默認可被點擊,那麼會繼續執行if語句中的內容,繼而回響應up事件,所以會輸出兩次
結果
④如果給TextView設置一個點擊事件的監聽,那麼也會輸出兩次結果,這是爲什麼呢?因爲在監聽
事件的源碼中有如下的一段代碼
public void setOnClickListener(OnClickListener l) {
//如果當前控件沒有點擊事件,設置一個點擊事件
if (!isClickable()) {
setClickable(true);
}
mOnClickListener = l;
}
就算TextView不可點擊,系統也會給它設置爲可點擊的,那麼他就可以和Button一樣了
2.ViewGroup
ViewGroup中事件分發和View有點不同,因爲ViewGroup有子View,這就會有事件的分發或者攔截了
每個ViewGroup都有以下三個方法
dispatchTouchEvent(); 負責事件的分發
onInterceptTouchEvent();負責事件的攔截
onTouchEvent(); 負責響應事件
ViewGroup佈局如下圖
首先是down事件的分發
ViewGroup①在分發事件之前會調用自己的onInterceptTouchEvent()方法判斷是否攔截,如果返
回false(不攔截),那麼分發給ViewGroup②的dispatchTouchEvent事件,它在分發之前也會判斷自己
是否要攔截,如果不攔截,那麼傳遞給子View③,這時③不能再向下分發啦,需要判斷onTouchEvent
是否消耗該down事件,如果返回爲True(不消耗),繼續向上返回給②的onTouchEvent,依次類推
在分發的過程中如果ViewGroup把事件攔截或者消耗掉了down事件,那麼後續的move,up等事件會直
接傳遞給它不會再走判斷的流程
三、小結
以上是對Android事件的簡單理解,其實我們在用手機的時候主要就是在touch手機屏幕,對touch的
原理搞明白了,那麼對於view是否該獲得事件,以及viewGroup是否該攔截事件都會非常清楚