上一篇我们讲了事件分发的过程,这一篇我们将会通过改变事件分发的过程解决滑动冲突
滑动冲突的常见场景
举个例子 我们常见的ViewPager和ListView嵌套时候时会出现滑动冲突,下面我们来自己处理一下这种冲突。
外部拦截法
@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;
//我们横向滑动的时候拦截,竖向滑动时交给listview自己去处理
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;
return intercepted;
}
内部拦截法
我们可以重写ListView的dispatchTouchEvent()方法
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
//要求父view不要拦截事件
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
//水平移动的增量
int deltaX = x - mLastX;
//竖直移动的增量
int deltaY = y - mLastY;
//当水平增量大于竖直增量时,表示水平滑动,此时需要父View去处理事件,让父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);
}
通过这两种方式我们就能解决大部分的滑动冲突
下面我们再来看图1-3这种冲突
这种情况其实也是根据上面两种方式来处理,我们可以根据滑动区域,来判断是否需要把滑动事件拦截自己处理,所以具体情况具体分析。
大家只用掌握上述滑动冲突的解决套路,不论场景是不同方向,还是同方向,还是乱七八糟的堆加在一起,就用套路去解决,万变不离其宗。根据上述的外部拦截和内部拦截法,可以看出外部拦截法实现起来更加简单,而且也符合View的正常事件分发机制,所以推荐使用外部拦截法(重写父View的onInterceptTouchEvent,父View决定是否拦截)来处理滑动冲突