解决方案:
1. 外部拦截法
2. 内部拦截法
外部拦截法
指通过父容器进行拦截处理,外部拦截需要重写父容器的onInterceptTouchEvent
方法,在内部做相应的拦截
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercept = false;//是否拦截
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
intercept = false;
break;
case MotionEvent.ACTION_MOVE:
if(父容器当前需要次事件){
intercept = true;
}else{
intercept = false;
}
break;
case MotionEvent.ACTION_UP:
intercept = false;
break;
}
return intercept;
}
注意:
在onInterceptTouchEvent
方法中的ACTION_DOWN 这个事件,父容器必须返回false, 即不拦截ACTION_DOWN事件,这是因为一旦父容器拦截了ACTION_DOWN,那么后面的ACTION_MOVE和 ACTION_UP 事件都会直接交由父容器处理,这个时候事件无法再传递给子控件,除非不需要子元素处理其他事件
ACTION_MOVE 事件:可以根据需求来决定是否拦截
ACTION_UP 事件:必须返回false,因为ACTION_UP事件本事没有太多意义
内部拦截法
是指父容器不拦截任何事件,所有的事件都传递给子元素,需要重写子元素的dispatchTouchEvent
方法,如果子元素需要此事件就直接消耗掉,否则就由父容器进行处理,这种方式跟android的事件分发机制不一致,需要配合getParent().requestDisallowInterceptTouchEvent(true);
方法,除了子元素需要做处理以外,父容器也要默认拦截除了ACTION_DOWN 以外的事件,这样当子元素调用getParent().requestDisallowInterceptTouchEvent(false);
方法时,父控件才能继续拦截所需事件
子控件
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
if(父容器需要此类事件){
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
case MotionEvent.ACTION_UP:
break;
}
return super.dispatchTouchEvent(ev);
}
父控件
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
return false;
} else {
return true;
}
}
相比之下外部拦截要比内部拦截简单些