事件分發(fā)過(guò)程由下列三個(gè)方法共同完成:
-
boolean dispatchTouchEvent (MotionEvent event)
用來(lái)進(jìn)行事件的分發(fā)官卡。如果事件可以傳遞給當(dāng)前View夯辖,那么此方法一定會(huì)被調(diào)用温赔。返回結(jié)果受當(dāng)前View的onTouchEvent和子View的dispatchTouchEvent返回結(jié)果的影響晒夹,表示是否消耗當(dāng)前事件嗤练。 -
boolean onInterceptTouchEvent (MotionEvent event)
在上述方法內(nèi)部調(diào)用楼誓,用來(lái)判斷是否攔截某個(gè)事件。如果當(dāng)前View攔截了某個(gè)事件沪伙,那么在同一個(gè)事件序列過(guò)程中瓮顽,該方法不會(huì)被再次被調(diào)用。返回結(jié)果表示是否攔截當(dāng)前事件围橡。 -
boolean onTouchEvent (MotionEvent event)
在dispatchTouchEvent方法中調(diào)用暖混,用來(lái)處理當(dāng)前事件。其中翁授,MotionEvent.ACTION_UP時(shí)會(huì)調(diào)用performClick方法儒恋,即mOnClickListener.onClick(this)方法善绎。返回結(jié)果表示是否消耗當(dāng)前事件黔漂,如果不消耗诫尽,則在同一個(gè)事件序列過(guò)程中,當(dāng)前View無(wú)法再次接收到事件炬守。
偽代碼表示事件傳遞規(guī)則:
ViewGroup的分發(fā)過(guò)程
public boolean dispatchTouchEvent(MotionEvent event) {
boolean consume = false;
if (onInterceptTouchEvent(event)) {
consume = super.dispatchTouchEvent(event);
} else {
consume = child.dispatchTouchEvent(event);
if (!consume) {
consume = super.dispatchTouchEvent(event);
}
}
return consume;
}
View的分發(fā)過(guò)程
public boolean dispatchTouchEvent(MotionEvent event) {
boolean consume = false;
if (mOnTouchListener.onTouch(this, event)) {
consume = true;
} else {
consume = onTouchEvent(event);
}
return consume;
}
demo效果
結(jié)論:
- 事件處理優(yōu)先級(jí)比較:OnTouchListener.onTouch > onTouchEvent > OnClickListener.onClick牧嫉。
- 同一個(gè)事件序列是指從手指觸摸屏幕的那一刻起,到手指離開(kāi)屏幕的那一刻結(jié)束减途,在這個(gè)過(guò)程中所產(chǎn)生的一系列事件酣藻。這個(gè)事件序列:down -- 若干個(gè)move -- up。
- 事件傳遞流程:Activity -> Window -> View鳍置。
- 當(dāng)一個(gè)View攔截一個(gè)事件后辽剧,那么這個(gè)事件序列都只能由它來(lái)處理,并且它的onInterceptTouchEvent方法不會(huì)再被調(diào)用税产。
- 正常情況下怕轿,一個(gè)事件序列只能被一個(gè)View攔截且消耗(特殊情況:View通過(guò)onTouchEvent將需要自己處理的事件強(qiáng)行傳遞給其他View)。
- 某個(gè)View一旦開(kāi)始處理事件辟拷,如果它不消耗ACTION_DOWN事件(onTouchEvent返回false)撞羽,那么同一事件序列中的其他事件都不會(huì)交給它來(lái)處理,而是重新交給它的父元素處理衫冻。
- 如果View不消耗ACTION_DOWN以外的其他事件诀紊,那么點(diǎn)擊事件會(huì)消失,此時(shí)父元素的onTouchEvent并不會(huì)被調(diào)用隅俘,并且當(dāng)前View可以持續(xù)收到后續(xù)事件邻奠,最終這些點(diǎn)擊事件交給Activity處理。
- ViewGroup默認(rèn)不攔截任何事件为居。
- View沒(méi)有onInterceptTouchEvent方法碌宴。
- View的onTouchEvent默認(rèn)都會(huì)消耗事件(返回true),除非它是不可點(diǎn)擊的颜骤。
應(yīng)用:滑動(dòng)沖突的解決
- 外部攔截法:重寫(xiě)父容器的onInterceptTouchEvent方法唧喉,判斷是否需要攔截
- 內(nèi)部攔截法:重寫(xiě)子View的dispatchTouchEvent方法,判斷是否消耗掉事件