Android中常见的滑动冲突主要分为三种:
1.外部滑动方向和内部滑动方向不一致
2.外部滑动方向和内部滑动方向一致
3.前两种的嵌套
既然滑动冲突都有既定的规律,那么解决滑动冲突也肯定有通用的方法.
外部滑动方向和内部滑动方向不一致
在这种情形下,我们可以根据滑动距离(水平距离和垂直距离)来判断滑动方向,并且来决定是该由外部View来拦截还是由内部View来拦截,简单的来说就是根据水平距离和垂直距离的比较来决定由哪个View来拦截,如果垂直方向距离比较大,那么就由垂直方向的View来进行拦截,反之则有水平方向的View来拦截.
具体实现主要有外部拦截和内部拦截两种方法.
外部拦截
所谓外部拦截就是所有的点击事件都由父容器来进行拦截处理,如果父容器需要处理该事件就进行拦截,返回true,否则就返回false;
外部拦截需要重写父容器的onInterceptTouchEvent()方法:
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;
break;
case MotionEvent.ACTION_MOVE:
if(父容器需要该点击事件)
intercepted = true;
else
intercepted = false;
break;
case MotionEvent.ACTION_UP:
intercepted = false;
break;
default:
break;
}
mLastXIntercept = x;
mLastYIntercept = y;
return intercepted
}
首先是ACTION_DOWN事件,该事件在父容器中必须不拦截,即返回false,因为如果一旦父容器拦截了ACTION_DOWN事件,那么ACTION_MOVE和ACTION_UP事件都会直接由父容器来处理,那么子View就无法处理想光的点击事件来.
另外就是ACTION_UP事件也必须返回false,也就是不要拦截,因为如果父容器中ACTION_UP返回了true,也就是拦截了,那么会导致子VIew的ACTION_UP事件无法响应,同时,onClick事件就无法执行了.这是父容器拦截中比较特殊,因为一旦父容器进行了拦截,那么后续的事件也就交由它自己处理了.(还记得上一篇所讲的总经理,部门经理和程序员场景吗?)
内部拦截
内部拦截就是所有的点击事件交由子View来处理,如果子View需要处理该事件就直接处理,否则才返回给父容器来处理.这种方法和Android的分发事件不太一样(子View不处理就相当于不处理了,不会返回给父容器),所以我们需要配合requestDisallowInterceptTouchEvent(阻止父view拦截点击事件)才能正常工作.
public boolean dispatchTouchEvent(MotionEvent event){
int x = (int)event.getX();
int y = (int)event.getY();
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
parent.requestDisallowInterceptTouchEvent(true);//父元素不拦截
break;
case MotionEvent.ACTION_MOVE:
int deltaX = x - mLastX;
int deltaY = y - mLastY;
if(父容器需要该点击事件)
parent.requestDisallowInterceptTouchEvent(fasle);//拦截
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
mLastX = x;
mLastY = y;
return super.dispatchTouchEvent(evnet);
}
需要注意的是,父元素要默认拦截除了ACTION_DOWN以外的其他事件,这样当子元素调用parent.requestDisallowInterceptTouchEvent(true);,父元素才能继续拦截所需的事件,原因主要是FLAG_DISALLOW_INTERCEPT这个标志位并不控制ACTION_DOWN,一旦父元素拦截了ACTION_DOWN,那么所有的事件就无法传递给子元素了.
public boolean onInterceptTouchEvent(MotionEvent event){
if (event.getAction() ==MotionEvent.ACTION_DOWN)
return false;
return true;
综上所述的话,比较建议使用外部拦截来处理常见的滑动冲突,而且这种做法是通用的,完全可以用来处理第二和第三种滑动冲突.