现在我们有竖向滑动的RecyclerView,在每个item内部又嵌套了一个横向滑动的RecyclerView,那么我们手指在滑动RecyclerVIew时,到底是竖向的响应还是横向的响应呢?
如图:红色线为手指滑动距离,右上方滑动到左下方;绿色为竖向滑动距离;蓝色为横向滑动距离;我们的期望是如果手指滑动的横向距离大于竖向距离的话就响应竖向的外层RecyclerVIew的滑动;如果手指移动的竖向距离大于横向距离,则滑动内部的横向的RecyclerView。
整体效果如下,完整项目:https://github.com/buder-cp/CustomView/tree/master/buder_DN_view/buderdn14
我们继承RecyclerView,重写其中的onInterceptTouchEvent方法,根据我们需要的业务逻辑去实现事件拦截:
public boolean onInterceptTouchEvent(MotionEvent e) {
if (e == null) {
return false;
}
int action = MotionEventCompat.getActionMasked(e);
int actionIndex = MotionEventCompat.getActionIndex(e);
switch (action) {
case MotionEvent.ACTION_DOWN:
scrollPointerId = MotionEventCompat.getPointerId(e, 0);
initialTouchX = Math.round(e.getX() + 0.5f);
initialTouchY = Math.round(e.getY() + 0.5f);
return super.onInterceptTouchEvent(e);
case MotionEvent.ACTION_POINTER_DOWN:
scrollPointerId = MotionEventCompat.getPointerId(e, actionIndex);
initialTouchX = Math.round(MotionEventCompat.getX(e, actionIndex) + 0.5f);
initialTouchY = Math.round(MotionEventCompat.getY(e, actionIndex) + 0.5f);
return super.onInterceptTouchEvent(e);
case MotionEvent.ACTION_MOVE:
int index = MotionEventCompat.findPointerIndex(e, scrollPointerId);
if (index < 0) {
return false;
}
int x = Math.round(MotionEventCompat.getX(e, index) + 0.5f);
int y = Math.round(MotionEventCompat.getY(e, index) + 0.5f);
if (getScrollState() != SCROLL_STATE_DRAGGING) {
int dx = x - initialTouchX;
int dy = y - initialTouchY;
boolean startScroll = false;
if (getLayoutManager().canScrollHorizontally() && Math.abs(dy) > touchSlop &&
(Math.abs(dx) > Math.abs(dy))) {
startScroll = true;
}
if (getLayoutManager().canScrollVertically() && Math.abs(dy) > touchSlop &&
(Math.abs(dy) > Math.abs(dx))) {
startScroll = true;
}
// if (getLayoutManager().canScrollVertically() && Math.abs(dy) > touchSlop &&
// (getLayoutManager().canScrollHorizontally() || Math.abs(dy) > Math.abs(dx))) {
// startScroll = true;
// }
return startScroll && super.onInterceptTouchEvent(e);
}
return super.onInterceptTouchEvent(e);
default:
return super.onInterceptTouchEvent(e);
}
}
上面重写的onInterceptTouchEvent方法中,所有代码都是源码,唯一不同的就是添加了我们自己业务判断的逻辑,横向距离和纵向距离的判断,添加了startScroll这个参数的判断
if (getLayoutManager().canScrollHorizontally() && Math.abs(dy) > touchSlop &&
(Math.abs(dx) > Math.abs(dy))) {
startScroll = true;
}
if (getLayoutManager().canScrollVertically() && Math.abs(dy) > touchSlop &&
(Math.abs(dy) > Math.abs(dx))) {
startScroll = true;
}