如何在NestedScrollView中使用RecyclerView?

Mec*_*cid 189 android android-recyclerview

RecyclerView里面怎么用NestedScrollViewRecyclerView设置适配器后内容不可见.

UPDATE布局代码已更新.

<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>
Run Code Online (Sandbox Code Playgroud)

Rah*_*yay 198

用您的recyclerView替换,

<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" />
Run Code Online (Sandbox Code Playgroud)

这里,

app:layout_behavior="@string/appbar_scrolling_view_behavior"
Run Code Online (Sandbox Code Playgroud)

将管理其余的事情.

还有一件事,不需要将您的recyclerView放在NestedScrollView中

  • 我无法理解为什么这个解决方案没有得到最多的投票.使用`NestedScrollView`无法实现,只需使用**`app:layout_behavior ="@ string/appbar_scrolling_view_behavior"`**.这是关键! (31认同)
  • 此解决方案旨在与`CoordinatorLayout`,'AppBarLayout`一起使用,并在应该使用`RecyclerView`滚动的子视图上设置适当的`layout_scrollFlags`.不知道为什么从答案中省略了这一点.否则,这是一个很好而简单的解决方案. (24认同)
  • 我认为了解RecyclerView的回收在这里不起作用是非常重要的.因此,如果您有一长串项目,它将显示一个明显的用户界面冻结. (4认同)
  • @RahulUpadhyay这对我有用,但我认为你的最后一行是错误的,如果它在NestedScrollView中,则RecyclerView根本不显示.但是,你是超级巨星:D (3认同)
  • 有用!只需更新recyclerview库编译'com.android.support:recyclerview-v7:+' (3认同)
  • 我找到了另一个解决方案 [Android 开发](https://plus.google.com/107404572903933672672/posts/Y8BNZeoxrrY) 它说你应该使用 `setMinimumHeight` 作为 `RecyclerView` 如果它在 `NestedScrollView` 或它将是 0。似乎这个小部件仍在工作。 (2认同)
  • 为我工作。我不明白@Gaket 的评论,因为我的 recyclerview 回收工作正常。 (2认同)

smb*_*now 117

更新1

自Android支持库23.2.0以来,setAutoMeasureEnabled(true)为LayoutManagers 添加了方法.它使RecyclerView能够包装它的内容并且像魅力一样工作.
http://android-developers.blogspot.ru/2016/02/android-support-library-232.html

所以只需添加以下内容:

    LayoutManager layoutManager = new LinearLayoutManager(this);
    layoutManager.setAutoMeasureEnabled(true);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setNestedScrollingEnabled(false);
Run Code Online (Sandbox Code Playgroud)


更新2

由于setAutoMeasureEnabled不推荐使用27.1.0 ,因此您应该使用重写方法提供LayoutManager的自定义实现isAutoMeasureEnabled()

但在使用RecyclerView的许多情况后,我强烈建议不要在包装模式下使用它,因为这不是它的目的.尝试使用具有多个项目类型的普通单个RecyclerView重构整个布局.或者使用我在下面描述的LinearLayout方法作为最后的手段


老答案(不推荐)

你可以RecyclerView在里面使用NestedScrollView.首先,您应该实现自己的自定义LinearLayoutManager,它会让您RecyclerView包装其内容.例如:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在那之后使用它LayoutManager为您的RecyclerView

recyclerView.setLayoutManager(new WrappingLinearLayoutManager(getContext()));
Run Code Online (Sandbox Code Playgroud)

但你也应该调用这两种方法:

recyclerView.setNestedScrollingEnabled(false);
recyclerView.setHasFixedSize(false);
Run Code Online (Sandbox Code Playgroud)

这里setNestedScrollingEnabled(false)禁用滚动RecyclerView,因此它不会拦截滚动事件NestedScrollView.并setHasFixedSize(false)确定适配器内容的更改可以更改大小RecyclerView

重要提示:这个解决方案在某些情况下很小,并且在性能方面存在问题,所以如果您有很多项目,RecyclerView我建议使用LinearLayout基于自定义的列表视图实现,为它创建适配器模拟并制作它表现得像ListViewRecyclerView

  • 警告!如果你的`RecyclerView`中有很多物品,请不要使用它. (18认同)
  • 自API级别27.1.0起不推荐使用setAutoMeasureEnabled https://developer.android.com/reference/android/support/v7/widget/RecyclerView.LayoutManager.html#setAutoMeasureEnabled(boolean) (2认同)
  • 改写boolean isAutoMeasureEnabled()。返回布局的测量遍是否应使用RecyclerView的AutoMeasure机制,还是应由LayoutManager的onMeasure(Recycler,State,int,int)实现来完成。默认情况下,此方法返回false(它实际上返回传递给不赞成使用的setAutoMeasureEnabled(boolean)的值),如果LayoutManager要由RecyclerView自动测量,则应重写此方法以返回true。如果重写此方法以返回true,则不应重写onMeasure(Recycler,State,int,int)。 (2认同)

Ash*_*rma 93

1)您需要使用上面的支持库23.2.0(或)

2)和RecyclerView高度wrap_content.

3) recyclerView.setNestedScrollingEnabled(false)

但通过这样做,回收者模式不起作用.(即所有视图将立即加载,因为wrap_content需要完整的高度,RecyclerView因此它将立即绘制所有子项View.没有视图将被回收).除非确实需要,否则尽量不要使用此模式util.尝试使用viewType,并补充说,需要滚动到所有其它视图RecyclerView,而不是使用RecyclerViewScrollview.性能影响将非常高.

为了简单起见"它只是像LinearLayout所有子视图一样"

  • 谢谢@Ashok.设置`recyclelerView.setNestedScrollingEnabled(false)`帮助我顺利滚动. (5认同)
  • 这应该是公认的答案!因为它很好地指出没有视图将被回收并且所有视图将立即被绘制. (3认同)
  • @AshokVarma,我现在面临同样的问题.但滚动在recyclerView内工作正常,但我无法实现recyclelerview的无端滚动,因为recyclelerview的所有视图立即绘制,因此它导致继续调用Web服务.那我该怎么处理呢? (2认同)
  • @AshokVarma 回收商行为问题有什么解决方案吗?我不希望 recyclerview 一次性绘制所有孩子。 (2认同)

zay*_*ayn 34

你可以用它android:fillViewport="true"NestedScrollView衡量RecyclerView.在RecyclerView将填补剩余的高度.所以如果你想滚动它NestScrollView,你可以设置RecyclerView's minHeight.

  • 如果您有200件物品的回收者视图,并且您这样做,嵌套的scrollview将展开以填充整个200件物品! (11认同)
  • @RJFares 这从来没有发生过。我尝试了一个演示并使用 LayoutInspector 来检查布局,它运行良好。你能提供你的 recyclerView 的版本吗? (2认同)
  • @zayn 我知道这是一个旧答案,但我们需要纠正这一点,RJFares 是正确的。RecyclerView 无论何种实现,当放入 NestedScrollView 中时都会停止回收项目,因此如果上面有 200 个项目,即使屏幕中不可见的项目也会消耗内存并且不会被回收,从而导致 OOM。 (2认同)

Vig*_*dar 26

简单地添加它recyclerView.setNestedScrollingEnabled(false);之前setAdapter为我工作.我没有添加app:layout_behavior="@string/appbar_scrolling_view_behavior"任何地方,也没有设置任何自定义布局管理器

<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>
Run Code Online (Sandbox Code Playgroud)

  • 但现在它不再回收视图了? (10认同)
  • 不,它没有,我尝试使用200个项目的非常复杂的布局,nestedscrollview只是扩展到其子项的大小,因此它将扩展,因此不会发生回收@MarkBuikema你是否设法找到更好的解决方案? (5认同)

小智 19

这对我有用

<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>
Run Code Online (Sandbox Code Playgroud)

  • 您可以删除第二个*app:layout_behavior ="@ string/appbar_scrolling_view_behavior"*因为行为仅适用于CoordinatorLayout直接子项. (3认同)
  • 此外,重要的是要提到您应该将 _Coordinator layout_ 作为您的根布局。这并不总是正确的。 (2认同)

Mar*_*ler 14

因为androidx它被称为androidx.core.widget.NestedScrollView- 它像黄油一样滚动isScrollContainermeasureAllChildren启用了属性:

<!-- 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>
Run Code Online (Sandbox Code Playgroud)


alc*_*san 7

尝试使用此库 - https://github.com/serso/android-linear-layout-manager.

库的LayoutManager使RecyclerView包装其内容.在这种情况下,RecyclerView将"与内部视图一样大",因此它不会有滚动条,用户将使用NestedScrollView的滚动功能.因此,它不会像"可滚动内部可滚动"一样模棱两可.


小智 7

你可以检查一个简单的测试代码

<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>
Run Code Online (Sandbox Code Playgroud)


Ant*_*aev 6

这是我用来避免滚动问题的代码:

mRecyclerView = (RecyclerView) view.findViewById(android.R.id.list);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mRecyclerView.getLayoutManager().setAutoMeasureEnabled(true);
mRecyclerView.setNestedScrollingEnabled(false);
mRecyclerView.setHasFixedSize(false);
Run Code Online (Sandbox Code Playgroud)


小智 6

我在NestedScrollView中使用了RecyclerView,它对我有用.我必须记住的唯一问题是NestedScrollView只接受一个子视图.所以在我的情况下,我使用了LienearLayout viewgroup,它包含了我的RecyclerView以及我需要的其他一些视图.

我遇到一个问题,将我的RecyclerView放在NestedScrollView中.我意识到滚动我的RecyclerView的内容松了一口气.

我后来意识到我的RecyclerView正在接收滚动事件,因此与NestedScrollView的滚动行为相冲突.

所以为了解决这个问题,我不得不用这种方法禁用我的RecyclerView的滚动功能 movieListNewRecyclerView.setNestedScrollingEnabled(false);

你可以在我的Instagram上查看我实际做过的简短视频.这是我的Instagram句柄ofelix03

点击此图片查看我的所作所为


Ish*_*ham 5

我在NestedScrollView中有Viewpager和RecyclerView。添加以下行后

recyclerView.setNestedScrollingEnabled(false);
recyclerView.setHasFixedSize(false);
Run Code Online (Sandbox Code Playgroud)

我解决了慢滚动和滚动滞后的问题。

  • 您不是说`recyclerView.setHasFixedSize(true);`吗? (3认同)

小智 5

如果你想在NestedScrollView中使用RecyclerView这是一个简单的技巧,只需设置:

回收视图

  • recyclerView.setHasFixedSize(false) (java/kt)

  • 机器人:nestedScrollingEnabled =“假”

  • 安卓:layout_height =“wrap_content”

  • android:overScrollMode="从不"

嵌套滚动视图

  • 机器人:fillViewport =“真”

这对我来说是工作,你也可以在 NestedScrollView 中使用许多 RecyclerView 。