Android開發(fā)藝術(shù)探索筆記——View(二)
View的事件分發(fā)機制
學(xué)習(xí)資料:
1.Understanding Android Input Touch Events System Framework
2.Managing Touch Events in a ViewGroup
3.Android事件傳遞機制
4.Input Events
5.Mastering the Android Touch System
6.MotionEvent
MotionEvent(運動事件)的傳遞規(guī)則
用戶每次觸摸屏幕都被包裝成了MotionEvent(運動事件)對象恶守。
屬性有:
-
動作碼(action code),如
ACTION_DOWN
,ACTION_UP
等等,用于描述用戶當(dāng)前的動作。 - 觸摸的橫縱坐標岔冀。
- 其它信息必指,如壓力,大小以及方向等等蜜笤。
View的事件分發(fā),就是對MotionEvent事件的分發(fā)過程惕味。
事件分發(fā)的三個重要方法:
//用于分發(fā)事件(dispatch touch event),要么將事件向下傳遞到目標View楼誓,要么交由自己處理。
//返回true表示自己處理
public boolean dispatchTouchEvent (MotionEvent event)
//用于攔截事件(intercept touch event),ViewGroup中有名挥,View中沒有這個方法疟羹。
public boolean onInterceptTouchEvent (MotionEvent event)
//用于處理事件
public boolean onTouchEvent (MotionEvent event)
三個方法的關(guān)系可用如下偽代碼描述:
public boolean dispatchTouchEvent(MotionEvent ev){
boolean consume = false;
if(onInterceptTouchEvent(ev)){
consume = true;
}else{
consume = child.dispatchTouchEvent(ev);
}
return consume;
}
View的onTouchListener
的優(yōu)先級比onTouchEvent
方法的高。
運動事件的傳遞順序:
Activity-->Window-->View
下面是將View
的dispatchTouchEvent()
方法設(shè)置斷點后禀倔,點擊ImageView
的調(diào)試過程:
能清楚地看到事件的傳遞過程和順序榄融。
若View的onTouchEvent()
方法返回false,則會調(diào)用它的父View的onTouchEvent()
方法救湖,依此類推愧杯,若調(diào)用順序上的所有View都不處理這個事件,則這個事件會最終傳遞給Activity的onTouchEvent()
方法鞋既。
View的事件分發(fā)機制類似于互聯(lián)網(wǎng)公司的工作流程:
新任務(wù):
CEO-->產(chǎn)品經(jīng)理-->CTO-->開發(fā)小組組長-->程序員
由上至下一級一級分發(fā)任務(wù)(dispatchTouchEvent)力九,如果是自己的任務(wù)(onInterceptTouchEvent)
,則攔截自己處理(onTouchEvent)邑闺,反之畏邢,則交由下級分發(fā)(child.dispatchTouchEvent)。
如果事情搞不定检吆,就一級一級向上拋(parent.onTouchEvent):
程序員-->開發(fā)組長-->CTO-->產(chǎn)品經(jīng)理-->CEO
事件傳遞機制的一些結(jié)論:
- 1.事件序列:從手指接觸屏幕到手指離開屏幕的過程舒萎,ACTION_DOWN-->ACTION_MOVE-->...-->ACTION_MOVE-->ACTION_UP
- 2.一個事件序列只能被一個View攔截且消費。
- 3.ViewGroup默認不攔截事件蹭沛。源碼中ViewGroup的
onInterceptTouchEvent()
方法默認返回false - 4.View沒有
onInterceptTouchEvent()
方法 - 5.事件傳遞是由外向內(nèi)(由上至下)的臂寝。事件先傳遞給父元素,然后再由父元素分發(fā)給子元素摊灭。通過
requestDisallowInterceptTouchEvent()
方法可以在子元素中干預(yù)父元素的事件分發(fā)過程咆贬。
事件分發(fā)源碼解析
Activity對事件的分發(fā)過程
- 1.點擊事件首先傳遞給
Activity
,然后由Activity
的dispatchTouchEvent()
方法進行事件的分發(fā)。Activity會將事件交由window進行分發(fā)帚呼。
//Activity源碼
...
/*
* Activity的dispatchTouchEvent方法
*/
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
//Activity交由window進行事件分發(fā)
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
- 2.Window將事件傳遞給DecorView(即ContentView的父View掏缎,可通過
Activity.getWindow().getDecorView()
方法獲取)。而Window類是抽象類煤杀,superDispatchTouchEvent()
方法是抽象方法眷蜈。
//Window類是抽象類
public abstract class Window {
...
//window的superDispatchTouchEvent方法是抽象方法
public abstract boolean superDispatchTouchEvent(MotionEvent event);
...
}
而PhoneWindow類是Window類的唯一實現(xiàn)類。
public class PhoneWindow extends Window implements MenuBuilder.Callback {
...
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
//PhoneWindow直接將事件交友DecorView處理
return mDecor.superDispatchTouchEvent(event);
}
...
}
可以看到PhoneWindow類在實現(xiàn)抽象方法superDispatchTouchEvent
時沈自,直接將事件交由DecorView處理酌儒。