滑动事件冲突
一般分三种:
- 滑动方向一致导致的冲突
- 滑动方向不一致导致的冲突
- 滑动方向的各种叠加导致的冲突
解决方案分两种:
-
外部拦截法
由外层父容器来处理,在父容器的onInterceptTouchEvent中决定是否需要拦截
-
内部拦截法
由内部子容器处理,在子容器中的dispatchTouchEvent中通过requestDiallowInterceptTouchEvent来申请父容器不拦截。
外部拦截
在父容器的onInterceptTouchEvent中决定是否需要拦截。
下面的父容器判断:水平方向大于竖直方向,则拦截
if (Math.abs(deltaX) > Math.abs(deltaY)) {
intercepted = true;
} else {
intercepted = false;
}
只需要根据需求改变判断的条件即可,完整代码:
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean intercepted = false;
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
intercepted = false;
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
intercepted = true;
}
break;
}
case MotionEvent.ACTION_MOVE: {
int deltaX = x - mLastXIntercept;
int deltaY = y - mLastYIntercept;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
intercepted = true;
} else {
intercepted = false;
}
break;
}
case MotionEvent.ACTION_UP: {
intercepted = false;
break;
}
default:
break;
}
Log.d(TAG, "intercepted=" + intercepted);
mLastX = x;
mLastY = y;
mLastXIntercept = x;
mLastYIntercept = y;
return intercepted;
}
内部拦截
内部拦截是子容器请求父容器不拦截的做法。需要配合requestDisallowInterceptTouchEvent使用。父容器也要稍微做些变动,相对来说复杂了点。
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
mHorizontalScrollViewEx2.requestDisallowInterceptTouchEvent(true);
break;
}
case MotionEvent.ACTION_MOVE: {
int deltaX = x - mLastX;
int deltaY = y - mLastY;
Log.d(TAG, "dx:" + deltaX + " dy:" + deltaY);
if (Math.abs(deltaX) > Math.abs(deltaY)) {
mHorizontalScrollViewEx2.requestDisallowInterceptTouchEvent(false);
}
break;
}
case MotionEvent.ACTION_UP: {
break;
}
default:
break;
}
mLastX = x;
mLastY = y;
return super.dispatchTouchEvent(event);
}
上面例子中,若水平方向上大于垂直方向,则交由父容器来处理,其他情况都有字容器来处理。所以父容器需要变动:
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
return false;
} else {
return true;
}
}
变动:若是ACTION_DOWN则不拦截,也不能拦截。其他时候都要拦截。这样只有在子容器请求父容器不拦截的时候才交由子容器来处理点击事件。