MotionEvent
所谓点击事件的事件分发,其实就是对MotionEvent事件的分发过程。即当一个MotionEvent产生了以后,系统需要把这个事件传递给一个具体的View,而这个传递的过程就是分发过程。
三个重要方法
public boolean dispatchTouchEvent(MotionEvent ev)
用来进行事件的分发。如果事件能够传递给当前View,就一定会调用这个方法,返回结果受当前View的onTouchEvent 和下级View的dispatchTouchEvent方法的影响。 表示 是否消耗当前的事件。
- return true; onTouchEvent 的ACTION_DOWN明确消耗
- return false; onTouchEvent 的ACTION_DOWN明确不消耗
- return child.dispatchTouchEvent; 由其子View确认是否消耗
public boolean onInterceptTouchEvent(MotionEvent event)
在 dispatchTouchEvent 内部调用,用来判断是否拦截事件。只会出现在ViewGroup中。如果当前View拦截了某个事件,那么在这个事件序列中,这个方法不会被再次调用。 返回结果表示 是否拦截当前事件
- return true; 拦截。子View不会再调用dispatchTouchEvent
- return false; 不拦截。 调用子View的dispatchTouchEvent
public boolean onTouchEvent(MotionEvent event)
在 dispatchTouchEvent 内部调用,用来处理点击事件。返回结果表示是否消耗当前事件,如果不消耗,则在该事件序列中,当前View无法再次接收到事件。
- return true; 消耗
- return false; 不消耗
三个方法的关系伪代码(简易分发)
public boolean dispatchTouchEvent(MontionEvent event){
boolean consume = false;
// 是否拦截 默认为false
if(onInterceptTouchEvent(event)){
// 确认拦截,看是否设置setOnTouchListener
if( has onTouchListener == true && onTouch == true){
consume = onTouch(event);
}else{
// 未设置OnTouchListener 或者 onTouch 为false,调用onTouchEvent
// onTouchEvent 的ACTION_DOWN 返回为true,则全部由该view处理剩下的MotionEvent
// onTouchEvent 的ACTION_DOWN 返回为false,则回退给父view处理剩下的MotionEvent
consume = onTouchEvent(event);
}
}else{
// 查看子类是否消耗事件
consume = child.dispatchTouchEvent(event);
// 如果子类不消耗,则再判断当前view 是否消耗
if(!consume){
// 看是否设置setOnTouchListener
if( has onTouchListener == true && onTouch == true){
consume = onTouch(event);
}else{
// 未设置OnTouchListener 或者 onTouch 为false,调用onTouchEvent
// onTouchEvent 的ACTION_DOWN 返回为true,则全部由该view处理剩下的MotionEvent
// onTouchEvent 的ACTION_DOWN 返回为false,则回退给父view处理剩下的MotionEvent
consume = onTouchEvent(event);
}
}
}
// 返回值为true 确认消耗事件,为false 则不消耗
return consume;
}
回退机制
子View一旦开始处理事件,如果不消耗ACTION_DOWN事件,即onTouchEvent(Event)返回false,那么同一事件 序列中的其他事件不会再交由该View处理,并且事件将重新交由它的父元素处理,即父View 的OnTouchEvent(Event)会被调用。