View的事件分發是指將MotionEvent分發到合適的View上的過程。
此過程由三個重要函數完成:
- public boolean diapatchTouchEvent(MotionEvent ev)
事件的分發
事件傳遞到當前View后觸發.如果事件能傳到View,此方法一定會被調用。
返回結果受當前View的onTouchEvent和下級的dispatchTouchEvent方法影響,表示當前View是否消耗當前事件。
public boolean onInterceptTouchEvent(MotionEvent ev)
在diapatchTouchEvent方法內部調用,表示是否攔截某個事件。
返回結果表示是否攔截當前事件。public boolean onTouchEvent(MotionEvent event)
在dispatchTouchEvent方法中調用,用來處理點擊事件,返回結果表示是否消耗當前事件。OnTouchListener
OnTouchListener的優先級高于OnTouchEvent。如果給View設置了OnTouchListener,那么它的onTouch方法會先于onTouchEventOnClickListener
OnClickListener在OnTouchEvent里面調用。如果設置了OnClickListener,在OnTouchEvent里面會調用其onClick方法,因此OnClickListener的優先級最低。
6.事件傳遞的過程Activity ->Window->View
下面的偽代碼概括了View事件分發的大致流程。
public boolean dispatchTouchEvent(MotionEvent event){
boolean consume = false;
if (onInterceptTouchEvent(ev)) {
if(mOnTouchListener != null){
if(!mOnTouchListener.onTouch()){
consume = onTouchEvent(ev);
}else{
consume = mOnTouchListener.onTouch();
}
}else{
consume = onTouchEvent(ev);
}
}else {
consume = child.dispatchTouchEvent(ev);
}
return consume;
}
幾點總結
某個View一旦決定攔截一個事件(onInterceptTouchEvent(ev)返回true),那么這個事件序列就只能由它處理,并且不會在調用其onInterceptTouchEvent
如果某個View開始處理事件,但它不消化ACTION_DOWN事件(onTouchEvent返回false),那么同一序列中的其他事件也不交給它處理,重新交由其父控件處理,父控件的onTouchEvent會被調用。
如果View不消耗ACTION_DOWN以外的事件,那么這個事件會消失,且父控件的onTouchEvent也不會調用,消失的事件交個Activity處理。
ViewGroup默認不攔截任何事件,onInterceptTouchEvent默認返回false。
View沒有onInterceptTouchEvent方法,一旦點擊事件傳遞過來,onTouchEvent方法就會被調用。
6.View的onTouchEvent默認是消耗事件(返回ture),除非它被設為不可點擊(clickable和longClickable都為false)。
- View的enable屬性不影響onTouchEvent的默認返回值。