这两天写了个离线音乐播放器,自定义了一个ViewGroup滑动菜单来展示音乐列表,长这样:
类似QQ 6.0的主页。
滑动冲突的出现
整个ViewGroup有两个子View,一个展示音乐列表一个展示播放详情。两个子View都需要被ViewDragHelper捕获到从而进行滑动菜单的左右滑动操作。可是在展示音乐列表的View中,有一个RecyclerView,那RecyclerView也需要滑动。在这里,滑动冲突就出现了,也就是说,我在触摸这个音乐列表这个View的时候,系统不知道我要上下滑动音乐列表还是左右滑动关闭菜单。
如何解决
上面说了,音乐列表View是RecyclerView展示的竖直方向的音乐列表,需要上下滑动。而外层ViewDragHelper需要左右滑动关闭/开启菜单。思路逐渐清晰:在onInterceptTouchEvent(MotionEvent event)方法里记录下X、Y轴的滑动距离,如果X轴距离大于Y轴距离,则是横滑,这个时候把事件交给ViewDragHelper,反之如果是竖向滑动,则把事件交给RecyclerView。
show the code:
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
canDrag = false;
mDownY = (int) event.getRawY();
mDownX = (int) event.getRawX();
break;
case MotionEvent.ACTION_MOVE:
int y = (int) event.getRawY();
int x = (int) event.getRawX();
int dDownY = y - mDownY;
int dDownX = x - mDownX;
//如果滑动达到一定距离
if (Math.abs(dDownX) > touchSlop || Math.abs(dDownY) > touchSlop) {
if (Math.abs(dDownX) > Math.abs(dDownY)){
canDrag = true;
}
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
canDrag = false;
break;
}
return canDrag || super.onInterceptTouchEvent(event);
}
可以看到,如果是横向滑动,则把事件拦截了。不再传递给RecyclerView。这个时候,滑动冲突就完美解决了。
在《Android开发艺术探索》一书中,这种在外部进行事件拦截判断的解决滑动冲突的方法成为外部拦截法。