BottomSheetBehavior下ViewPager2的滑动问题

BottomSheetBehavior下ViewPager2的滑动问题

该布局结构下,ViewPager2下的RecyclerView无法响应滑动。

BottomSheetBehavior下ViewPager2的滑动问题_第1张图片
ViewPager2上的RecyclerView充当Tab作用

问题点

现象:BottomSheetBehavior可以正常折叠,展开,收起。展开状态下,滑动ViewPager2,无反应。BottomSheetBehavior可以正常响应事件,同时,事件被拦截无法传递到ViewPager2中。

为啥会被拦截?

在onInterceptTouchEvent的返回值,有这样一串逻辑:

View scroll = nestedScrollingChildRef != null ? nestedScrollingChildRef.get() : null;
    return action == MotionEvent.ACTION_MOVE
        && scroll != null
        && !ignoreEvents
        && state != STATE_DRAGGING
        && !parent.isPointInChildBounds(scroll, (int) event.getX(), (int) event.getY())
        && viewDragHelper != null
        && Math.abs(initialY - event.getY()) > viewDragHelper.getTouchSlop();

isPointInChildBounds比较特殊,用于判断手势在不在"scroll"活动范围内。

nestedScrollingChildRef取值逻辑

在onLayoutChild中通过findScrollingChild赋值。

View findScrollingChild(View view) {
    if (ViewCompat.isNestedScrollingEnabled(view)) {
      return view;
    }
    if (view instanceof ViewGroup) {
      ViewGroup group = (ViewGroup) view;
      for (int i = 0, count = group.getChildCount(); i < count; i++) {
        View scrollingChild = findScrollingChild(group.getChildAt(i));
        if (scrollingChild != null) {
          return scrollingChild;
        }
      }
    }
    return null;
  }

通过判断isNestedScrollingEnabled来决定,并且是布局中的第一个。那应该就是布局中ViewPage2上方的RecyclerView了,将其nestedScrollingEnabled设为false试试看效果,结果ViewPage2部分可以上下滑动了,BottomSheetBehavior又不能展开了。根据对嵌套滑动的了解,RecyclerView在响应滑动事件的同时,也会将事件传递到父View中,也就意味着是BottomSheetBehavior响应的触发逻辑出了问题。onNestedPreScroll中有这样一段逻辑,判断是不是同一个view。

@Override
  public void onNestedPreScroll(
      @NonNull CoordinatorLayout coordinatorLayout,
      @NonNull V child,
      @NonNull View target,
      int dx,
      int dy,
      @NonNull int[] consumed,
      int type) {

        ...

    View scrollingChild = nestedScrollingChildRef != null ? nestedScrollingChildRef.get() : null;
    if (target != scrollingChild) {
      return;
    }

        ...

  }

target是真正滑动的view,即ViewPage2 item中的RecyclerView。而scrollingChild则成了ViewPager2的内部实现RecyclerViewImpl。从而导致BottomSheetBehavior不会同步滑动。那么就简单了,反射将RecyclerViewImpl的nestedScrollingEnabled关闭,就可以修正这一问题。

但随之而来一个新的问题,在切换tab的时候(也就是ViewPager2上方的RecyclerView),仍然会失效。原因也很简单,nestedScrollingChildRef仍然是ViewPager2中前一个item中的View。

如何修复?

重新触发nestedScrollingChildRef的赋值逻辑,因在layout的过程中赋值,只要requestLayout就可以达到目的。或者直接反射修改值。

总结

将BottomSheetBehavior中所有子View的isNestedScrollingEnabled设置false,除了需要响应滑动的RecyclerView。并在ViewPager2切换页面的时候,触发CoordinatorLayout.requestLayout()或反射修改nestedScrollingChildRef值。

你可能感兴趣的:(BottomSheetBehavior下ViewPager2的滑动问题)