View的滑动冲突处理
1、滑动冲突的解决方式:
1.1外部拦截法:
所谓的外部拦截法是指点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截,如果不需要此事件就不拦截,这样就可以解决滑动冲突的问题,这种方法比较符合点击事件的分发机制。外部拦截法需要重写父容器的onInterceptTouchEvent方法,在内部做相应的拦截即可。
外部拦截法的典型逻辑(伪代码)
private int mLastXIntercept = 0; //分别记录上次滑动的坐标
private int mLastYIntercept = 0;
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercepted = false;
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
//这里必须是false,即不拦截ACTION_DOWN事件
//因为一旦拦截后续的MOVE和UP事件都必须交由父容器处理,这时候事件就无法再传递给子元素了
intercepted = false;
break;
case MotionEvent.ACTION_MOVE:
int deltaX=x-mLastXIntercept;
int deltaY=y-mLastYIntercept;
//根须需要决定是否需要拦截
if (如果父容器需要点击事件) {
intercepted = true;
} else {
intercepted = false;
}
break;
case MotionEvent.ACTION_UP:
//这里必须返回false因为UP事件本身没有太多意义
intercepted = false;
break;
}
mLastXIntercept = x;
mLastYIntercept = y;
return intercepted;
}
1.2内部拦截法:
内部拦截法是指父容器不拦截任何事件,所有的事件都传递给志愿书,如果子元素需要此事件就直接消耗掉,否则就交由父容器进行处理,这种方法和Android中的事件分发机制不一致,需要配合requestDisallowInterceptTouchEvent方法才能正常工作,使用起来相比较外部拦截法稍显复杂。
内部拦截法的典型逻辑(伪代码)
1.重写子元素的dispatchTouchEvent方法
private int mLastX = 0; //分别记录上次滑动的坐标
private int mLastY = 0;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
int deltaX=x-mLastX;
int deltaY=y-mLastY;
//根须需要决定是否需要拦截
if (如果父容器需要点击事件) {
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
case MotionEvent.ACTION_UP:
//这里必须返回false因为UP事件本身没有太多意义
break;
}
mLastX = x;
mLastY = y;
return super.dispatchTouchEvent(ev);
}
2.重写父元素的onInterceptTouchEvent方法
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
if(action = MotionEvent.ACTION_DOWN){
return false;
}else{
return true;
}
}