当我们内外两层View都可以滑动时候,就会产生滑动冲突!
- 1.外层与内层滑动方向不一致,外层ViewGroup是可以横向滑动的,内层View是可以竖向滑动的(类似ViewPager,每个页面里面是ListView)
- 2.外层与内层滑动方向一致,外层ViewGroup是可以竖向滑动的,内层View同样也是竖向滑动的(类似ScrollView包裹ListView)
注: 一场景有外部处理和内部处理两种发誓,二场景主要看逻辑实现
解决方案有两种,外部处理和内部处理
外部拦截法:
// 外层view 的 onInterceptTouchEvent
private int mLastX;
private int mLastY;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercepted = false;
int x = (int) ev.getX();
int y = (int) ev.getY();
final int action = ev.getAction() & MotionEvent.ACTION_MASK;
switch (action) {
case MotionEvent.ACTION_DOWN:
intercepted = false;
//调用ViewPager的onInterceptTouchEvent方法初始化mActivePointerId
super.onInterceptTouchEvent(ev);
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;
}
mLastXIntercept = x;
mLastYIntercept = y;
LogUtil.e(TAG,"intercepted = "+intercepted);
return intercepted;
}
Math.abs(deltaX)>Math.abs(deltaY)表示横向位移增量大于竖向位移增量,即水平滑动,则拦截事件。
注意:
- ACTION_DOWN 一定返回false,不要拦截它,否则根据View事件分发机制,后续ACTION_MOVE 与 ACTION_UP事件都将默认交给父View去处理!
- 原则上ACTION_UP也需要返回false,如果返回true,并且滑动事件交给子View处理,那么子View将接收不到ACTION_UP事件,子View的onClick事件也无法触发。而父View不一样,如果父View在ACTION_MOVE中开始拦截事件,那么后续ACTION_UP也将默认交给父View处理!
private int mLastX;
private int mLastY;
// 内层view 的 onInterceptTouchEvent
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int x = (int) ev.getX();
int y = (int) ev.getY();
final int action = ev.getAction() & MotionEvent.ACTION_MASK;
switch (action) {
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
//水平移动的增量
int deltaX = x - mLastX;
//竖直移动的增量
int deltaY = y - mLastY;
//当水平增量大于竖直增量时,表示水平滑动,此时需要父View去处理事件
if (Math.abs(deltaX) > Math.abs(deltaY)){
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
mLastX = x;
mLastY = y;
return super.dispatchTouchEvent(ev);
}
// 外层view 的 onInterceptTouchEvent
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction() & MotionEvent.ACTION_MASK;
if (action == MotionEvent.ACTION_DOWN){
super.onInterceptTouchEvent(ev);
return false;
}
return true;
}