View的滑动冲突
- 外部滑动方法和内部滑动方向不一致
- 根据滑动时水平的还是竖直的
- 滑动路径和水平方向所成的夹角
- 水平方法和竖直方向的距离差
- 水平和竖直方向的速度差来做判断
- 根据滑动时水平的还是竖直的
- 外部滑动方向和内部滑动方向一致
- 从业务上进行区分
- 上面两种情况的嵌套
- 用1和2的方法一起使用进行区分
解决方法
外部拦截法
父容器决定事件是否拦截
[伪代码]
public boolean onInterceptHoverEvent(MotionEvent event) {
boolean intercepted = false;
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//必须为false
//NOTE:如果在ACTION_DOWN返回true,那么后续的ACTION_MOVE和ACTION_UP
//事件都会直接交给父容器处理,这个时候就没法再传递给子元素了
intercepted = false;
break;
case MotionEvent.ACTION_MOVE:
if (isParentNeed()) { //父容器需要当前点击事件
intercepted = true;
} else {
intercepted = false;
}
break;
case MotionEvent.ACTION_UP:
//必须返回false,因为ACTION_UP本身没有太多意义
intercepted = false;
break;
default:
break;
}
mLastXIntercept = x;
mLastYIntercept = y;
return intercepted;
}
内部拦截法
父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交由父容器进行处理。需要requestDisallowInterceptTouchEvent方法。
[伪代码]
public boolean dispatchTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
int deltaX = x - mLastX;
int deltaY = y - mLastY;
if (isParentNeed()) { //父容器需要此点击事件
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
case MotionEvent.ACTION_UP:
break;
default:
}
mLastX = x;
mLastY = y;
return super.dispatchTouchEvent(event);
}
除了子元素需要做处理以外,父元素也要默认拦截除了ACTION_DOWN以外的其他事件,这样当子元素调用parent.requestDisallowInterceptTouchEvent(false)时,父元素才能继续拦截所需的事件。
public boolean onInterceptHoverEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
return false;
} else {
return true;
}
}
为什么父容器不能拦截ACTION_DOWN?
ACTION_DOWN事件不接受不接受FLAG_DISALLOW_INTERCEPT这个标志位的控制,所以一旦父容器拦截ACTION_DOWN事件,那么所有的事件都无法传递到子元素中去,这样内部拦截也就无法起作用了。
其他
笔记于《Android艺术开发探索》