先创建个ViewGroupA和ViewB,然后我们来看看事件是怎么传递的。
public class ViewGroupA extends RelativeLayout {
...
/**
* 传递事件
*
* @param ev
* @return
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.d("touch", "ViewGroupA : dispatchTouchEvent");
return super.dispatchTouchEvent(ev);
}
/**
* 拦截事件
*
* @param ev
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.d("touch", "ViewGroupA : onInterceptTouchEvent");
return super.onInterceptTouchEvent(ev);
}
/**
* 处理事件
*
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d("touch", "ViewGroupA : onTouchEvent");
return super.onTouchEvent(event);
}
}
这里没有直接继承ViewGroup 而是RelativeLayout,主要是为好布局。其实一样的RelativeLayout就是继承的ViewGroup。
public class ViewB extends View {
....
/**
* 事件传递
*
* @param event
* @return
*/
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.d("touch", "ViewB : dispatchTouchEvent");
return super.dispatchTouchEvent(event);
}
/**
* 事件处理
*
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d("touch", "ViewB : onTouchEvent");
return super.onTouchEvent(event);
}
}
布局文件:
显示效果:
点击蓝色区域即ViewB,然后我们看下日志输出:
D/touch: ViewGroupA : dispatchTouchEvent
D/touch: ViewGroupA : onInterceptTouchEvent
D/touch: ViewB : dispatchTouchEvent
D/touch: ViewB : onTouchEvent
D/touch: ViewGroupA : onTouchEvent
从日志输出顺序可以看出,事件由Activity-->ViewGroupA 如果ViewGroupA不拦截
事件由ViewGroupA-->ViewB 当前ViewB为最上面一层View,如果ViewB不处理,那么ViewB就将事件又返回给ViewGroupB 交由他的onTouchEvent处理
试下ViewGroupA将事件拦截了,看看日志输出:
修改ViewGroupA代码:
/**
* 拦截事件
*
* @param ev
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.d("touch", "ViewGroupA : onInterceptTouchEvent");
return true;
}
日志输出:
D/touch: ViewGroupA : dispatchTouchEvent
D/touch: ViewGroupA : onInterceptTouchEvent
D/touch: ViewGroupA : onTouchEvent
我们发现没有关于ViewB的输出,这说明我们的事件拦截成功了,ViewB没有接受到此次事件。
现在我们来看下ViewGroupA输出的顺序:
1.dispatchTouchEvent
2.onInterceptTouchEvent
3.onTouchEvent
我们可以猜测为:事件传递给ViewGroupA,如果ViewGroupA不传递给子View(ViewB),说明那么他就会走onTouchEvent,即为自己处理。
现在我们看下,如果我们拦截后不处理当前事件会怎样:
public class ViewGroupA extends RelativeLayout {
...
/**
* 拦截事件
*
* @param ev
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("touch", "ViewGroupA : onInterceptTouchEvent MotionEvent.ACTION_DOWN ");
return true;
case MotionEvent.ACTION_UP:
Log.d("touch", "ViewGroupA : onInterceptTouchEvent MotionEvent.ACTION_UP ");
return false;
case MotionEvent.ACTION_CANCEL:
Log.d("touch", "ViewGroupA : onInterceptTouchEvent MotionEvent.ACTION_CANCEL ");
return false;
default:
return false;
}
}
}
输出日志:
D/touch: ViewGroupA : dispatchTouchEvent MotionEvent.ACTION_DOWN
D/touch: ViewGroupA : onInterceptTouchEvent MotionEvent.ACTION_DOWN
D/touch: ViewGroupA : onTouchEvent MotionEvent.ACTION_DOWN
D/touch: TouchDispatchActivity onTouchEvent: MotionEvent.ACTION_DOWN
D/touch: TouchDispatchActivity onTouchEvent: MotionEvent.ACTION_UP
如果我们拦截后,处理了又怎样,将ViewGroupA中的onTouchEvent的Down事件返回为true:
/**
* 处理事件
*
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("touch", "ViewGroupA : onTouchEvent MotionEvent.ACTION_DOWN ");
return true;
case MotionEvent.ACTION_UP:
Log.d("touch", "ViewGroupA : onTouchEvent MotionEvent.ACTION_UP ");
break;
case MotionEvent.ACTION_CANCEL:
Log.d("touch", "ViewGroupA : onTouchEvent MotionEvent.ACTION_CANCEL ");
break;
}
return super.onTouchEvent(event);
}
显示日志:
D/touch: ViewGroupA : dispatchTouchEvent MotionEvent.ACTION_DOWN
D/touch: ViewGroupA : onInterceptTouchEvent MotionEvent.ACTION_DOWN
D/touch: ViewGroupA : onTouchEvent MotionEvent.ACTION_DOWN
D/touch: ViewGroupA : dispatchTouchEvent MotionEvent.ACTION_UP
D/touch: ViewGroupA : onTouchEvent MotionEvent.ACTION_UP
D/touch: TouchDispatchActivity onTouchEvent: MotionEvent.ACTION_UP
综合上面两个输出可以得出结论:
1.如果一个View拦截了,那么这个事件接下来的系列都会由他处理,并且不会调用onInterceptTouchEvent()。
2.如果一个View拦截,那么如果他不处理,那么这个事件接下来的系列就会交由他的父类来处理,即由其父类的onTouchEvent()来处理。
现在在ViewGroupA里不拦截,在ViewB中只处理Down
public class ViewB extends View {
...
/**
* 事件处理
*
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("touch", "ViewB onTouchEvent: ACTION_DOWN ");
return true;
case MotionEvent.ACTION_UP:
Log.d("touch", "ViewB onTouchEvent: ACTION_UP ");
return false;
case MotionEvent.ACTION_CANCEL:
Log.d("touch", "ViewB onTouchEvent: ACTION_CANCEL ");
return false;
default:
return false;
}
}
}
日志输出:
D/touch: ViewGroupA : dispatchTouchEvent MotionEvent.ACTION_DOWN
D/touch: ViewGroupA : onInterceptTouchEvent MotionEvent.ACTION_DOWN
D/touch: ViewB dispatchTouchEvent: ACTION_DOWN
D/touch: ViewB onTouchEvent: ACTION_DOWN
D/touch: ViewGroupA : dispatchTouchEvent MotionEvent.ACTION_UP
D/touch: ViewGroupA : onInterceptTouchEvent MotionEvent.ACTION_UP
D/touch: ViewB dispatchTouchEvent: ACTION_UP
D/touch: ViewB onTouchEvent: ACTION_UP
D/touch: TouchDispatchActivity onTouchEvent: MotionEvent.ACTION_UP
3.如果View不消耗除Down之外的其实事件,那么这个点击事件会消失,此时父View(VIewGroupA)的onTouchEvent()不会调用,并且当前的VIew可接收到持续事件,最终这些小时的点击事件会传给Activity处理
我们现在不拦截Down,只拦截UP看看会怎样:
public class ViewGroupA extends RelativeLayout {
...
/**
* 拦截事件
*
* @param ev
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("touch", "ViewGroupA : onInterceptTouchEvent MotionEvent.ACTION_DOWN ");
return false;
case MotionEvent.ACTION_UP:
Log.d("touch", "ViewGroupA : onInterceptTouchEvent MotionEvent.ACTION_UP ");
return true;
case MotionEvent.ACTION_CANCEL:
Log.d("touch", "ViewGroupA : onInterceptTouchEvent MotionEvent.ACTION_CANCEL ");
return false;
default:
return false;
}
}
}
日志输出:
D/touch: ViewGroupA : dispatchTouchEvent MotionEvent.ACTION_DOWN
D/touch: ViewGroupA : onInterceptTouchEvent MotionEvent.ACTION_DOWN
D/touch: ViewB dispatchTouchEvent: ACTION_DOWN
D/touch: ViewB onTouchEvent: ACTION_DOWN
D/touch: ViewGroupA : dispatchTouchEvent MotionEvent.ACTION_UP
D/touch: ViewGroupA : onInterceptTouchEvent MotionEvent.ACTION_UP
D/touch: ViewB dispatchTouchEvent: ACTION_CANCEL
D/touch: ViewB onTouchEvent: ACTION_CANCEL
D/touch: TouchDispatchActivity onTouchEvent: MotionEvent.ACTION_UP
我们发现传递了down事件,拦截up事件的话,子View就会走ACTION_CANCEL。