1.外部拦截
//外部拦截的话只需要复写onInterceptTouchEvent
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercepted = false;
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
//这个时候返回false,事件才能交给子view 进行处理
intercepted = false;
break;
case MotionEvent.ACTION_MOVE:
if(父布局需要拦截){
intercepted = true;
}else{
intercepted = false;
}
break;
case MotionEvent.ACTION_UP:
//这个时候也要返回false,因为返回true的话,子View 得到不了ACTION_UP事件,如果为false,当前ViewGroup也不会在这里面
//拦截事件因为 父布局拦截的话ACTION_MOVE 已经返回true了,这个时候不会调用onInterceptTouchEvent方法,所以还会调用父布局的
//OnToucheEvent();
intercepted = false;
break;
}
return intercepted;
}
2.内部拦截
子View的方法
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
ViewGroup viewGroup = (ViewGroup) getParent();
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
if(父布局需要拦截){
if(viewGroup != null){
//不允许父布局拦截
viewGroup.requestDisallowInterceptTouchEvent(true);
}
}
break;
case MotionEvent.ACTION_MOVE:
//父布局需要拦截的时候
if(viewGroup != null){
//允许父布局拦截
viewGroup.requestDisallowInterceptTouchEvent(false);
}
break;
case MotionEvent.ACTION_UP:
break;
}
return super.dispatchTouchEvent(ev);
}
父布局的方法
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
if(action == MotionEvent.ACTION_DOWN){
//交给子view处理 ,只有这设置成false,才会走到子View的dispatch
return false;
}else{
//一直自己处理,但是因为action_down的时候已经交给子View 处理了,子View 设置的是 disallowIntercept为true
// 父布局的标识这个时候不允许拦截
//这个时候根本不会走disallowIntercept 为false的时候,这个时候才会拦截
return true;
}
}
总结:单独复写子View的方法,不能保证事件分发流转到子view因为父布局会对事件进行拦截,所以要先复写父布局的方法,对比1.外部拦截法来说这个明显的复杂,所以建议使用外部拦截法
事件分发的原理参考上一篇博客Android 事件分发机制:https://blog.csdn.net/u010939317/article/details/107430746