- 涉及到的几个概念:
同一个事件序列:手指接触屏幕的那一刻起,到手指离开屏幕的那一刻结束。这个过程中产生的一系列事件,以down事件开始,中间可能包含多个move事件,最终以up事件结束。正常情况下,一个事件序列只能被一个view拦截且消耗,特殊情况下,这个view也可以将本该自己处理的事件通过onTouchEvent强行传递给子view处理。
- 事件传递规则
public boolean dispatchTouchEvent(MotionEvent ev)用于事件分发。返回结果表示是否消耗当前事件。
public boolean onInterceptTouchEvent(MotionEvent ev)只有ViewGroup有该方法。用来判断是否拦截某个事件。返回结果表示是否拦截当前事件。默认返回false
onTouchEvent(MotionEvent event)具体处理事件。返回结果表示是否消耗当前事件。如果不消耗,在同一个事件序列中,当前view无法再次接受到该事件。
上述3个方法关系伪代码如下(摘自《Android开发艺术探索》):
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean consume=false;
if(onInterceptTouchEvent(ev))
{
consume=onTouchEvent(ev);
}else{
consume= child.dispatchTouchEvent();//由下级view的dispatchTouchEvent()决定。
}
return consume;
}
注意:当一个view被设置了OnTouchListener,这时OnTouchListener中的onTouch方法会优先于这个View的onTouchEvent方法。当且仅当OnTouchListener中的onTouch返回false时View自己的onTouchEvent会被执行。
因此改进后的事件传递伪代码如下:
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean consume=disallowIntercept;//由子View设置给父View
if(!consume)
{
consume=onInterceptTouchEvent(ev);
}
if(consume)
{
if(mOnTouchListener!=null)
{
consume=mOnTouchListener.onTouch(this,ev);//优先执行
}
if(!consume)
{
consume=onTouchEvent(ev);
}
}else{
consume= child.dispatchTouchEvent();
}
return consume;
}
事件传递顺序:Activity->Window->View