How to use RecyclerView inside NestedScrollView?

前端 未结 24 2431
抹茶落季
抹茶落季 2020-11-22 03:39

How to use RecyclerView inside NestedScrollView? RecyclerView content is not visible after setting adapter.

UPDATE

相关标签:
24条回答
  • 2020-11-22 04:21

    There is a simple and testing code u may check

    <android.support.v4.widget.NestedScrollView
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:fillViewport="true"
         app:layout_behavior="@string/appbar_scrolling_view_behavior">
        <android.support.v7.widget.RecyclerView
               android:layout_width="match_parent"
               android:layout_height="match_parent"/>
       </android.support.v4.widget.NestedScrollView>
    
    0 讨论(0)
  • 2020-11-22 04:21

    I used RecyclerView inside a NestedScrollView and it worked for me. The only gotcha I had to keep in mind was that a NestedScrollView takes only one child view. So in my case I used of LienearLayout viewgroup which was housing my RecyclerView plus a number of other views that I needed.

    I experience one issue putting my RecyclerView inside the NestedScrollView. I realized that scrolling the content of my RecyclerView slacked.

    I later realized that my RecyclerView was receiving the scrolling event and therefore was conflicting with the scrolling behavior of the NestedScrollView.

    So to solve that problem, I had to disable the scroll functionality of my RecyclerView with this method movieListNewRecyclerView.setNestedScrollingEnabled(false);

    You can checkout my Instagram for a short video of what I actually did. This is my instagram handle ofelix03

    Click this image to see what I did

    0 讨论(0)
  • 2020-11-22 04:22

    Try to use this library - https://github.com/serso/android-linear-layout-manager.

    LayoutManager of the library makes RecyclerView wraps its contents. In this case RecyclerView will be "as big as inner views", so it will not have a scrollbars and user will use scrolling abilities of NestedScrollView. Therefore, it will not be ambiguous like "scrollable inside scrollable".

    0 讨论(0)
  • 2020-11-22 04:22

    do not use recyclerView inside NestedScrollView. it may cause cascading problems! I suggest using ItemViewTypes in RecyclerView for handling multiple kinds of views. just add a RecyclerView with match_parent width and height. then in your recyclerViewAdapter override getItemViewType and use position for handling what layout to be inflated. after that you can handle your view holder by using onBindViewHolder method.

    0 讨论(0)
  • 2020-11-22 04:26

    UPDATE 1

    Since Android Support Library 23.2.0 there were added method setAutoMeasureEnabled(true) for LayoutManagers. It makes RecyclerView to wrap it's content and works like a charm.
    http://android-developers.blogspot.ru/2016/02/android-support-library-232.html

    So just add something like this:

        LayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setAutoMeasureEnabled(true);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setNestedScrollingEnabled(false);
    


    UPDATE 2

    Since 27.1.0 setAutoMeasureEnabled is deprecated, so you should provide custom implementation of LayoutManager with overridden method isAutoMeasureEnabled()

    But after many cases of usage RecyclerView I strongly recommend not to use it in wrapping mode, cause this is not what it is intended for. Try to refactor whole your layout using normal single RecyclerView with several items' types. Or use approach with LinearLayout that I described below as last resort


    Old answer (not recommended)

    You can use RecyclerView inside NestedScrollView. First of all you should implement your own custom LinearLayoutManager, it makes your RecyclerView to wrap its content. For example:

    public class WrappingLinearLayoutManager extends LinearLayoutManager
    {
    
        public WrappingLinearLayoutManager(Context context) {
            super(context);
        }
    
        private int[] mMeasuredDimension = new int[2];
    
        @Override
        public boolean canScrollVertically() {
            return false;
        }
    
        @Override
        public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
                int widthSpec, int heightSpec) {
            final int widthMode = View.MeasureSpec.getMode(widthSpec);
            final int heightMode = View.MeasureSpec.getMode(heightSpec);
    
            final int widthSize = View.MeasureSpec.getSize(widthSpec);
            final int heightSize = View.MeasureSpec.getSize(heightSpec);
    
            int width = 0;
            int height = 0;
            for (int i = 0; i < getItemCount(); i++) {
                if (getOrientation() == HORIZONTAL) {
                    measureScrapChild(recycler, i,
                            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                            heightSpec,
                            mMeasuredDimension);
    
                    width = width + mMeasuredDimension[0];
                    if (i == 0) {
                        height = mMeasuredDimension[1];
                    }
                } else {
                    measureScrapChild(recycler, i,
                            widthSpec,
                            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                            mMeasuredDimension);
    
                    height = height + mMeasuredDimension[1];
                    if (i == 0) {
                        width = mMeasuredDimension[0];
                    }
                }
            }
    
            switch (widthMode) {
                case View.MeasureSpec.EXACTLY:
                    width = widthSize;
                case View.MeasureSpec.AT_MOST:
                case View.MeasureSpec.UNSPECIFIED:
            }
    
            switch (heightMode) {
                case View.MeasureSpec.EXACTLY:
                    height = heightSize;
                case View.MeasureSpec.AT_MOST:
                case View.MeasureSpec.UNSPECIFIED:
            }
    
            setMeasuredDimension(width, height);
        }
    
        private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                int heightSpec, int[] measuredDimension) {
    
            View view = recycler.getViewForPosition(position);
            if (view.getVisibility() == View.GONE) {
                measuredDimension[0] = 0;
                measuredDimension[1] = 0;
                return;
            }
            // For adding Item Decor Insets to view
            super.measureChildWithMargins(view, 0, 0);
            RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
            int childWidthSpec = ViewGroup.getChildMeasureSpec(
                    widthSpec,
                    getPaddingLeft() + getPaddingRight() + getDecoratedLeft(view) + getDecoratedRight(view),
                    p.width);
            int childHeightSpec = ViewGroup.getChildMeasureSpec(
                    heightSpec,
                    getPaddingTop() + getPaddingBottom() + getDecoratedTop(view) + getDecoratedBottom(view),
                    p.height);
            view.measure(childWidthSpec, childHeightSpec);
    
            // Get decorated measurements
            measuredDimension[0] = getDecoratedMeasuredWidth(view) + p.leftMargin + p.rightMargin;
            measuredDimension[1] = getDecoratedMeasuredHeight(view) + p.bottomMargin + p.topMargin;
            recycler.recycleView(view);
        }
    }
    

    After that use this LayoutManager for your RecyclerView

    recyclerView.setLayoutManager(new WrappingLinearLayoutManager(getContext()));
    

    But you also should call those two methods:

    recyclerView.setNestedScrollingEnabled(false);
    recyclerView.setHasFixedSize(false);
    

    Here setNestedScrollingEnabled(false) disable scrolling for RecyclerView, so it doesn't intercept scrolling event from NestedScrollView. And setHasFixedSize(false) determine that changes in adapter content can change the size of the RecyclerView

    Important note: This solution is little buggy in some cases and has problems with perfomance, so if you have a lot of items in your RecyclerView I'd recommend to use custom LinearLayout-based implementation of list view, create analogue of Adapter for it and make it behave like ListView or RecyclerView

    0 讨论(0)
  • 2020-11-22 04:27

    For androidx it's called androidx.core.widget.NestedScrollView - and it scrolls alike butter with properties isScrollContainer and measureAllChildren enabled:

    <!-- Scrolling Content -->
    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
    
        android:isScrollContainer="true"
        android:measureAllChildren="true"
    
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
    
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fastScrollEnabled="true"
            android:scrollbarStyle="insideInset"
            android:scrollbars="vertical"
            android:splitMotionEvents="false"
            android:verticalScrollbarPosition="right"/>
    
    </androidx.core.widget.NestedScrollView>
    
    0 讨论(0)
提交回复
热议问题