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方法会先于onTouchEvent -
OnClickListener
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的默认返回值。
网友评论