How to use RecyclerView inside NestedScrollView?
如何在
设置适配器后,
UPDATE布局代码已更新。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="@dimen/keyline_1"> </RelativeLayout> <View android:id="@+id/separator" android:layout_width="match_parent" android:layout_height="1dp" android:background="#e5e5e5" /> <android.support.v7.widget.RecyclerView android:id="@+id/conversation" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> </android.support.v4.widget.NestedScrollView> |
将您的recyclerView替换为
1 2 3 4 5 | <android.support.v7.widget.RecyclerView android:id="@+id/conversation" app:layout_behavior="@string/appbar_scrolling_view_behavior" android:layout_width="match_parent" android:layout_height="wrap_content" /> |
这里,
1 | app:layout_behavior="@string/appbar_scrolling_view_behavior" |
将管理其余的事情。
还有一件事,无需将您的recyclerView放在NestedScrollView内
更新1
从Android支持库23.2.0开始,为LayoutManagers添加了方法
http://android-developers.blogspot.ru/2016/02/android-support-library-232.html
因此,只需添加如下内容:
1 2 3 4 | LayoutManager layoutManager = new LinearLayoutManager(this); layoutManager.setAutoMeasureEnabled(true); recyclerView.setLayoutManager(layoutManager); recyclerView.setNestedScrollingEnabled(false); |
更新2
由于不建议使用27.1.0
但是在很多情况下使用RecyclerView后,我强烈建议不要在包装模式下使用它,因为这不是它的预期用途。尝试使用具有多个项目类型的普通单个RecyclerView重构整个布局。或使用我在下面描述的最后一种方法使用LinearLayout
旧答案(不推荐)
您可以在
首先,您应该实现自己的自定义
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | 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); } } |
之后,将此
1 | recyclerView.setLayoutManager(new WrappingLinearLayoutManager(getContext())); |
但是您还应该调用这两个方法:
1 2 | recyclerView.setNestedScrollingEnabled(false); recyclerView.setHasFixedSize(false); |
在这里,
重要说明:在某些情况下,此解决方案几乎没有错误,并且在性能方面存在问题,因此,如果您在
1)您需要使用以上的支持库23.2.0(或)
2)和
3)
但是,这样做将导致回收站模式无效。 (即所有视图将被立即加载,因为
简单起见,"它在所有子视图中都充当
您可以使用
在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | <android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="15dp" android:layout_marginRight="15dp" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="@color/white" android:text="Some Text..." android:padding="15dp" /> </LinearLayout> <LinearLayout android:orientation="vertical" android:padding="15dp" android:layout_marginTop="10dp" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Quick Links" android:textColor="@color/black" android:textStyle="bold" android:textAllCaps="true" android:paddingLeft="20dp" android:drawableLeft="@drawable/ic_trending_up_black_24dp" android:drawablePadding="10dp" android:layout_marginBottom="10dp" android:textSize="16sp"/> <View android:layout_width="fill_parent" android:layout_height="1dp" android:background="#efefef"/> <android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/recyclerview" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> </LinearLayout> </android.support.v4.widget.NestedScrollView> |
这对我有用
1 2 3 4 5 6 7 8 9 10 11 12 | <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:id="@+id/rv_recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> </android.support.v4.widget.NestedScrollView> |
您可以检查一个简单的测试代码
1 2 3 4 5 6 7 8 9 | <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> |
对于
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <!-- 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> |
尝试使用此库-https://github.com/serso/android-linear-layout-manager。
该库的LayoutManager使得RecyclerView包装其内容。在这种情况下,RecyclerView将"与内部视图一样大",因此它将没有滚动条,并且用户将使用NestedScrollView的滚动功能。因此,它不会像" scrollable inside scrollable"那样模棱两可。
这是我用来避免滚动问题的代码:
1 2 3 4 5 | mRecyclerView = (RecyclerView) view.findViewById(android.R.id.list); mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); mRecyclerView.getLayoutManager().setAutoMeasureEnabled(true); mRecyclerView.setNestedScrollingEnabled(false); mRecyclerView.setHasFixedSize(false); |
我在NestedScrollView中使用了RecyclerView,它对我有用。我要记住的唯一陷阱是NestedScrollView仅包含一个子视图。因此,在我的情况下,我使用了LienearLayout视图组,该视图组容纳了我的RecyclerView以及我需要的许多其他视图。
我将RecyclerView放入NestedScrollView时遇到一个问题。我意识到滚动RecyclerView的内容很费劲。
后来我意识到我的RecyclerView正在接收滚动事件,因此与NestedScrollView的滚动行为发生冲突。
因此,要解决该问题,我必须使用此方法
您可以在我的Instagram上查看我实际所做的简短视频。这是我的Instagram句柄ofelix03
点击此图片查看我做了什么
我在NestedScrollView中有Viewpager和RecyclerView。添加以下行后
1 2 | recyclerView.setNestedScrollingEnabled(false); recyclerView.setHasFixedSize(false); |
我解决了缓慢滚动和滚动滞后的问题。
如果您使用的是
在您的布局中添加RecyclerView,如下所示:
1 2 3 4 5 | <android.support.v7.widget.RecyclerView android:id="@+id/review_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:scrollbars="vertical" /> |
并在您的Java文件中:
1 2 3 4 5 6 | RecyclerView mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView); LinearLayoutManager layoutManager=new LinearLayoutManager(getContext()); layoutManager.setAutoMeasureEnabled(true); mRecyclerView.setLayoutManager(layoutManager); mRecyclerView.setHasFixedSize(true); mRecyclerView.setAdapter(new YourListAdapter(getContext())); |
在这里
查看此问题和此开发者博客以获取更多信息。
您不能在嵌套滚动视图中使用回收者视图。它不打算包含更多的可滚动视图,而是因为它是滚动布局本身的子级,因此您需要嵌套的滚动视图。我遇到了同样的问题,但最后我将textview移到了recyclerview的标题视图中,使recyclerview成为协调器布局的直接子级,并删除了嵌套的滚动视图。然后我所有的问题都消失了。
保留recyclerview的回收功能并避免recyclerview加载所有数据的一种解决方案是在recyclerview本身中设置固定高度。通过这样做,recyclerview仅限于加载,只要它的高度可以显示给用户,就可以在滚动到底部/顶部时回收其元素。
有很多好的答案。关键是必须将
1 | mRecyclerView.setNestedScrollingEnabled(false); |
而且您还有机会在xml代码(
1 2 3 4 5 | <android.support.v7.widget.RecyclerView android:id="@+id/recyclerview" android:nestedScrollingEnabled="false" android:layout_width="match_parent" android:layout_height="match_parent" /> |
如果您在NestedScrollView中使用RecyclerView ScrollListener,则同时使用addOnScrollListener侦听器将无法正常工作。
使用此代码。
1 2 3 4 5 6 7 | recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); ...... } }); |
此代码在NestedScrollView内的RecyclerView ScrollListener正常工作。
谢谢
不要在NestedScrollView中使用recyclerView。可能会导致级联问题!
我建议在RecyclerView中使用ItemViewTypes处理多种视图。
只需添加具有match_parent宽度和高度的RecyclerView。然后在您的recyclerViewAdapter中重写getItemViewType并使用position处理要放大的布局。之后,您可以使用onBindViewHolder方法处理视图持有者。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | nestedScrollView.setNestedScrollingEnabled(true); mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); //... } }); <androidx.core.widget.NestedScrollView android:id="@+id/nested" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" android:layout_below="@id/appBarLayout_orders" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <androidx.constraintlayout.widget.ConstraintLayout ... <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler" android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"/> |
我必须通过工具栏滚动来实现CoordinatorLayout,这使我整日忙于解决这一问题。我已经通过完全删除NestedScrollView使它工作。所以我只是在根目录使用RelativeLayout。
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/rv_nearby" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> </RelativeLayout> |
就我而言,NestedScrollview的子级是ConstraintLayout。 它没有按预期工作,我将其替换为LinearLayout。 也许对某人有帮助。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <androidx.core.widget.NestedScrollView android:id="@+id/nestedScrollView" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:descendantFocusability="blocksDescendants"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="0dp" android:layout_height="wrap_content" android:nestedScrollingEnabled="false" app:layout_constraintBottom_toTopOf="@+id/divider" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tinTitle"/> </LinearLayout> </androidx.core.widget.NestedScrollView> |
我使用了这个很棒的扩展(用kotlin编写,但也可以用Java编写)
https://github.com/Widgetlabs/expedition-nestedscrollview
基本上,您可以在任何包中找到
1 2 3 4 | <com.your_package.utils.NestedRecyclerView android:id="@+id/rv_test" android:layout_width="match_parent" android:layout_height="match_parent" /> |
查看Marc Knaup的这篇很棒的文章
https://medium.com/widgetlabs-engineering/scrollable-nestedscrollviews-inside-recyclerview-ca65050d828a
Solution for not to load all recyclew view child at once inside nested
scroll view.
Benfits:
解决:
in your xml instead of using match_parent or wrap_content for
recycleview use fix height.
带NestedScrollView的RecyclerView
1 2 3 4 5 | <android.support.v7.widget.RecyclerView android:id="@+id/rv" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> |