所有的view的滑动冲突都可以用如下2种方式来解决:
外部拦截法和内部拦截法
1.外部拦截法:
所谓外部拦截法是指点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截,如果不要此事件就不拦截,外部拦截发法需要重写父容器的onInterceptTouchEvent方法,在内部做相应的拦截即可,外代码如下
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercept = false;
int x = (int) ev.getRawX();
int y = (int) ev.getRawY();
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:
//up事件本身没有多大的意义,默认不拦截
intercept = false;
break;
default:
break;
}
return intercept;
}
,这里对上述代码在描述一下:在onInterceptTouchEvent方法中,首先是ACTION_DOWN事件,父容器必须返回false,即不拦截down事件,因为如果父容器拦截了down事件,那么后续的move和up事件就都会交给父容器处理,这时候就再没法传递给子元素了,其次是move事件,这个事件可根据需求来决定是否拦截,如果父容器拦截就返回true,否则返回false,最后是up事件,这里必须返回false,因为up事件本事没有太多意义
2.内部拦截法:
内部拦截法是指父容器不拦截任何事情,所有的事件都传第给子元素,如果子元素需要此事件就直接消耗掉,否则就通过设置getParent().requestDisallowInterceptTouchEvent(false) 交由父元素处理,父元素和子元素都要有所改动
子元素的伪代码如下(我们需要重写子元素的dispatchTouchEvent方法)
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int x = (int) ev.getRawX();
int y = (int) ev.getRawY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
//让父元素把所有的事件都先给子元素
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
if (子元素不要此事件/父容器需要此点击事件) {
//false;让父元素去拦截事件
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return super.dispatchTouchEvent(ev);
}
当面对不同的滑动策略时,我们只需要修改里面的条件即可,其他不需要做改动,而对于父元素也要默认拦截除了action_down事件以外的其他事件,这样当子元素调用parent.requestDisallowInterceptTouchEvent(false)方法时,父元素才能继续拦截所需的事件
(为什么父元素不拦截子元素的down事件呢,因为如果父元素拦截了down事件,子元素就不会接受到事件了,后续的事件就都交给父元素处理了)
父元素的修改如下:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action=ev.getAction();
if( action=MotionEvent.ACTION_MOVE){
//不拦截事件
return false
}else{
//父元素想拦截事件,
//当子元素设置成getParent().requestDisallowInterceptTouchEvent(false);父元素就可以拿到事件了,
//如果是true,父元素就拿不到事件
return true;
}
}
至于具体的实例Demo,容我后续在接着补上去啦~