带有自定义LayoutManager的RecyclerView无法在NestedScrollView中滚动

时间:2018-01-29 20:03:03

标签: android android-recyclerview

如果RecyclerView嵌套在NestedScrollview中,则不会进行滚动。放置在LinearLayout中时 - 滚动项是正常的。

NestedScrollView位于CoordinatorLayout内部,NestedScrollView设置为peekHeight,并设置为屏幕高度的2/3。 我需要先将列表滚动到第一个元素,然后NestedScroll接收。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:orientation="vertical"
              android:layout_width="match_parent"
              app:behavior_hideable="false"
              app:behavior_peekHeight="@dimen/ttn_list_peek_height"
              app:layout_behavior="@string/bottom_sheet_behavior"
              android:layout_height="wrap_content">

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="visible"
        android:descendantFocusability="blocksDescendants"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        >
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            >
        <android.support.v7.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scrollbars="vertical"/>

        <FrameLayout
            android:layout_width="match_parent"
            android:background="@color/app_background"
            android:visibility="gone"
            android:layout_height="wrap_content">

            <ProgressBar
                android:layout_gravity="center_horizontal"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>

        </FrameLayout>
        </LinearLayout>
 </android.support.v4.widget.NestedScrollView>
</LinearLayout>

Init RecyclerView:

MyLayoutManager lm = new MyLayoutManager(mContext);
lm.setAutoMeasureEnabled(true);
rcHistoryList.setLayoutManager(lm);
rcHistoryList.setAdapter(historyAdapter);
rcHistoryList.setHasFixedSize(false);
rcHistoryList.setNestedScrollingEnabled(false);

LayoutManager使用偏移量一个接一个地分解元素 - 以创建重叠元素的效果。

 public class MyLayoutManager extends RecyclerView.LayoutManager {

      private static final String TAG = "ScrollManager";

      private SparseArray<View> viewCache = new SparseArray<>();

      private Context context;

      private int mAnchorPos;

      public MyLayoutManager(Context context)
      {

      }

      @Override
      public boolean canScrollVertically() {
        return true;
      }

      @Override
      public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
        int delta = scrollVerticallyInternal(dy);
        offsetChildrenVertical(-delta);
        fill(recycler);
        return delta;

      }

      private int scrollVerticallyInternal(int dy) {
        int childCount = getChildCount();
        int itemCount = getItemCount();
        if (childCount == 0){
          return 0;
        }

        final View topView = getChildAt(0);
        final View bottomView = getChildAt(childCount - 1);

        int viewSpan = getDecoratedBottom(bottomView) - getDecoratedTop(topView);
        if (viewSpan <= getHeight()) {
          return 0;
        }

        int delta = 0;

        if (dy < 0){
          View firstView = getChildAt(0);
          int firstViewAdapterPos = getPosition(firstView);
          if (firstViewAdapterPos > 0){
            delta = dy;
          } else {
            int viewTop = getDecoratedTop(firstView);
            delta = Math.max(viewTop, dy);

          }
        } else if (dy > 0){
          View lastView = getChildAt(childCount - 1);
          int lastViewAdapterPos = getPosition(lastView);
          if (lastViewAdapterPos < itemCount - 1){ 
            delta = dy;
          } else {
            int viewBottom = getDecoratedBottom(lastView);
            int parentBottom = getHeight();
            delta = Math.min(viewBottom - parentBottom, dy);
          }
        }
        return delta;
      }

      private View getAnchorView() {
        int childCount = getChildCount();
        HashMap<Integer, View> viewsOnScreen = new HashMap<>();
        Rect mainRect = new Rect(0, 0, getWidth(), getHeight());
        for (int i = 0; i < childCount; i++) {
          View view = getChildAt(i);
          int top = getDecoratedTop(view);
          int bottom = getDecoratedBottom(view);
          int left = getDecoratedLeft(view);
          int right = getDecoratedRight(view);
          Rect viewRect = new Rect(left, top, right, bottom);
          boolean intersect = viewRect.intersect(mainRect);
          if (intersect){
            int square = viewRect.width() * viewRect.height();
            viewsOnScreen.put(square, view);
          }
        }
        if (viewsOnScreen.isEmpty()){
          return null;
        }
        Integer maxSquare = null;
        for (Integer square : viewsOnScreen.keySet()) {
          if (maxSquare == null){
            maxSquare = square;
          } else {
            maxSquare = Math.max(maxSquare, square);
          }
        }
        return viewsOnScreen.get(maxSquare);
      }

      private void fill(RecyclerView.Recycler recycler) {

        View anchorView = getAnchorView();
        viewCache.clear();

        for (int i = 0, cnt = getChildCount(); i < cnt; i++) {
          View view = getChildAt(i);
          int pos = getPosition(view);
          viewCache.put(pos, view);
        }

        for (int i = 0; i < viewCache.size(); i++) {
          detachView(viewCache.valueAt(i));
        }

        fillDown1(recycler);
        fillUp1(recycler);

        for (int i=0; i < viewCache.size(); i++) {
          recycler.recycleView(viewCache.valueAt(i));
        }

      }

      @Override
      public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        detachAndScrapAttachedViews(recycler);
        fill(recycler);
      }

      private void fillUp1(RecyclerView.Recycler recycler) {
        boolean fillUp = true;
        int pos = 0; //anchorPos - 1;
        int viewBottom = 0;// = anchorTop;

        while (fillUp && pos >= 0){
          View view = viewCache.get(pos);
          if (view == null){
            view = recycler.getViewForPosition(pos);
            addView(view, 0);
            measureChildWithMargins(view, 0, 0);
            layoutDecorated(view, 0, viewBottom - getDecoratedMeasuredHeight(view), getDecoratedMeasuredWidth(view), viewBottom);
          } else {
            attachView(view, 0);
            viewCache.remove(pos);
          }
          viewBottom = getDecoratedTop(view);
          fillUp = (viewBottom > 0);
          pos--;
        }
      }

      private void fillDown1(RecyclerView.Recycler recycler) {
        int pos = 0;
        boolean fillDown = true;
        int height = getHeight();
        int viewTop = 0;
        int itemCount = getItemCount();
        View view1 = recycler.getViewForPosition(getChildCount());
        pos = getChildCount();
        viewTop = getDecoratedTop(view1);
        while (fillDown && pos < itemCount){
          View view = viewCache.get(pos);

          if (view == null){
            view = recycler.getViewForPosition(pos);
            addView(view);
            measureChildWithMargins(view, 0, 0); 
            layoutDecorated(view, 0, viewTop, getDecoratedMeasuredWidth(view), viewTop + getDecoratedMeasuredHeight(view));
    viewHeight);
          }
          else
          {
            attachView(view);
            viewCache.remove(pos);
          }
          viewTop = getDecoratedBottom(view) - 70;
          fillDown = viewTop <= height;
          pos++;
        }

      }

      @Override
        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
          return new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT);
        }
    }

1 个答案:

答案 0 :(得分:0)

将Recyclervirw可滚动属性设置为false。

mRecyclerView.setNestedScrollingEnabled(假);