事件分发过程
事件分发是从Activity开始,从上到下,依次通过window,DecorView向下分发。关键的几个方法是
- dispatchTouchEvent()
- onInterceptTouchEvent()
- OnTouchListener.onTouch()
- onTouchEvent()
对于一个根ViewGroup来说,事件产生后首先会传递给他,这时他的dispatchTouchEvent()就会被调用
若这个ViewGroup的onInterceptTouchEvent()返回true,表示自己要拦截这个事件,那么他的onTouchEvent就会被调用;
若onInterceptTouchEvent()返回false,会交给子控件去处理,依次向下传递,直到事件被处理。
当一个View要处理事件时,若设置了onTouchListener,会先调用onTouch()。
若onTouch()返回true,onTouchEvent()就不会被调用了;
若onTouch()返回false,会调用onTouchEvent();
onTouchEvent若返回true,表示事件被消费,后续同一个序列的事件都会交给他来处理;
onTouchEvent若返回false,表示事件未被消费,同一个事件序列的后续事件交给其父控件来处理。若一直未被处理,Activity的onTouchEvent就会被调用。
总结伪代码如下
//整体的处理逻辑,从上级往下级分发,
//如果下级能处理了,这个事件就消费掉了,
//如果处理不了,会再传递给上级处理
boolean Parent.dispatchTouchEvent(MotionEvent ev) {
if (child.dispatchTouchEvent(ev)) {
return true;
}
boolean consume= this.onTouch();
if(!consume){
consume = this.onTouchEvent(ev)
}
return consume;
}
//ViewGroup的处理过程
//如果上级拦截了,就不向下传递,由上级处理
//如果上级不拦截,就交给下级处理,调用child的dispatchTouchEvent()
boolean viewGroup.dispatchTouchEvent(){
boolean consume = false;
//viewGroup拦截了事件(即重写了onInterceptTouchEvent()并返回true)
if(onInterceptTouchEvent()){
consume = this.onTouch()/onTouchEvent()
}else {
consume = child.dispatchTouchEvent();
}
return consume;
}
//View的处理过程
//如果设置了onTouchListener(),onTouch()会被调用
//如果onTouch()返回true,事件消费掉
//如果onTouch()返回false,执行onTouchEvent()方法
//如果可点击且设置了setOnclickListener(),会调用onClick()
child.dispatchTouchEvent{
//调用了setOnTouchListener()
if(mTouchListener != null){
//如果onTouch()返回true,直接return;
if(onTouch()){
return true;
}
}
//如果onTouch()没有执行或返回的false
onTouchEvent(){
if(clickable == true){
switch(event.getAction){
//调用了setOnClickListener()
if(mOnclickListener != null){
onClick();
}
}
//往后的事件可以执行的原因
return true;
}
return false;
}
}
一些结论:
- 同一事件序列是指从手指按下开始到手指抬起结束,由一个Down,多个MOVE,一个UP组成
- 正常情况下,一个事件序列只能被一个View拦截并消耗。
- 某个ViewGroup一旦拦截事件,那么同一事件序列都由该ViewGroup处理,且onInterceptTouchEvent()不会再次执行。
- 某个View开始处理事件,若不处理Down事件(onTouchEvent返回了false),那么后续事件也不会交给他来处理,而是交给父控件来处理
- View的onTouchEvent默认是会处理事件的,除非clickable是 false
- View的enable属性并不影响onTouchEvent的默认返回值,只要View的clickable是true,onTouchEvent就会返回true
水平有限,有错误欢迎指正
网友评论