理解了TouchEvent之后,就是为了更好的解决滑动冲突。网上找到两种的解决办法,因为不一定非要固定的方法解决,就先记录这两种方式,并写了个小Demo.
转载自 http://blog.csdn.net/a992036795/article/details/51735501
解决横竖滑动冲突,水平也是一样的,只是判定条件就需要根据具体情况来处理了。
1)外部拦截解决,在ViewGroup来决定传递来的事件由自己处理还是交给ChildView来处理。修改parentView就可了。
/**
* 拦截事件
* @param ev
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercepted = false;
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (ev.getAction()) {
/*如果拦截了Down事件,则子类不会拿到这个事件序列*/
case MotionEvent.ACTION_DOWN:
lastXIntercept = x;
lastYIntercept = y;
intercepted = false;
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
intercepted = true;
}
break;
case MotionEvent.ACTION_MOVE:
final int deltaX = x - lastXIntercept;
final int deltaY = y - lastYIntercept;
/*根据条件判断是否拦截该事件*/
if (Math.abs(deltaX) > Math.abs(deltaY)) {
intercepted = true;
} else {
intercepted = false;
}
break;
case MotionEvent.ACTION_UP:
intercepted = false;
break;
}
lastXIntercept = x;
lastYIntercept = y;
return intercepted;
}
关键部分就是重写onInterceptTouchEvent这个方法,来完成拦截,这里在Down的时候,没有拦截事件,这样就能够找到TargetView,可以将事件传递到target,但是在MOVE的时候写了逻辑,需要拦截条件:
X方向上的滑动大于Y方向的滑动的就返回true自己处理,切换LIstView。
X方向上的滑动小于Y方向的滑动就返回false交由ListView处理,ListView上下滚动。
2)内部拦截解决,在parentView中,拦截逻辑如下:
/**
* 拦截事件
* @param ev
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
return true;
}
return false;
} else {
return true;
}
}
Down事件不拦截,就可以找打targetView,后续的事件才有机会传递下去,其他事件统一都拦截掉,ChildView的修改如下。
/**
* 使用 outter.requestDisallowInterceptTouchEvent();
* 来决定父控件是否对事件进行拦截
*
* @param ev
* @return
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mHorizontalEx2.requestDisallowInterceptTouchEvent(true); //设置标记为不parent让拦截
break;
case MotionEvent.ACTION_MOVE:
final int deltaX = x - lastXIntercepted;
final int deltaY = y - lastYIntercepted;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
mHorizontalEx2.requestDisallowInterceptTouchEvent(false); //设置标记为让parent拦截
}
break;
case MotionEvent.ACTION_UP:
break;
}
lastXIntercepted = x;
lastYIntercepted = y;
return super.dispatchTouchEvent(ev);
}
在ViewGroup中,贴一段代码
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
} else {
// There are no touch targets and this action is not an initial down
// so this view group continues to intercept touches.
intercepted = true;
}
这里当时其他的事件的时候由于targe!=null,可以在这里根据Flag决定是否调用这个拦截函数。
requestDisallowInterceptTouchEvent(true)就是设置的mFlag,为FLAGDISALL_DISALLOW_INTERCETP,上面的parentView中的重写之后,当其他事件只要调用就是拦截下来,由parent处理。
targetView中定义逻辑,当
X方向上的滑动大于Y方向的滑动就让parent拦截下来,parent处理
X方向上的滑动小于Y方向的滑动就不让parent拦截下来,自己处理
这样在View内部就可以干涉到parent的事件处理过程。来决定谁来处理这些事件
demo地址点击打开链接