如何在NestedScrollView中使用RecyclerView?

时间:2015-06-23 10:18:19

标签: android android-recyclerview

如何在RecyclerView内使用NestedScrollView? 设置适配器后,RecyclerView内容不可见。

更新布局代码已更新。

<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>

26 个答案:

答案 0 :(得分:184)

将recyclerView替换为,

NSWindows

这里,

<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" />

将管理其余的事情。

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

答案 1 :(得分:112)

更新1

自Android支持库23.2.0以来,为LayoutManagers添加了方法setAutoMeasureEnabled(true)。它使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);


更新2

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

但经过多次使用后,我强烈建议不要在包装模式中使用它,因为这不是它的目的。尝试使用具有多个项目类型的普通单个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);
    }
}

之后使用此LayoutManager作为RecyclerView

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

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

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

此处setNestedScrollingEnabled(false)禁用RecyclerView的滚动,因此它不会拦截来自NestedScrollView的滚动事件。 setHasFixedSize(false)确定适配器内容的更改可以更改RecyclerView

的大小

重要提示:此解决方案在某些情况下很小,并且在性能方面存在问题,因此如果您RecyclerView中有很多项目,我建议使用自定义{基于{1}}的列表视图实现,为其创建Adapter的模拟,并使其行为类似于LinearLayoutListView

答案 2 :(得分:88)

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

2)和RecyclerView高度为wrap_content

3)recyclerView.setNestedScrollingEnabled(false)

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

为了简单起见,它只是作为LinearLayout充当所有子视图&#34;

答案 3 :(得分:34)

您可以使用android:fillViewport="true"NestedScrollView衡量RecyclerViewRecyclerView将填充剩余的高度。因此,如果您要滚动NestScrollView,可以设置RecyclerView的{​​{1}}。

答案 4 :(得分:25)

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>

答案 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>

答案 6 :(得分:7)

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

库的LayoutManager使RecyclerView包装其内容。在这种情况下,RecyclerView将与内部视图一样大#34;因此它不会有滚动条,用户将使用NestedScrollView的滚动功能。因此,它不会像'#34;可滚动内部滚动&#34;。

那样含糊不清

答案 7 :(得分: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>

答案 8 :(得分:6)

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

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

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

所以要解决这个问题,我必须使用这种方法movieListNewRecyclerView.setNestedScrollingEnabled(false);

禁用我的RecyclerView的滚动功能

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

Click this image to see what I did

答案 9 :(得分:6)

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

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

答案 10 :(得分:4)

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

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

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

答案 11 :(得分:3)

您无法在嵌套滚动视图中使用回收站视图。它并不打算包含进一步的可滚动视图,但这是因为它是滚动布局本身的子项,您需要嵌套的滚动视图。我有同样的问题,但最后我将textview移动到recyclelerview中的headerview,使recyclerview成为协调器布局的直接子项,并删除了嵌套的滚动视图。然后我的所有问题都消失了。

答案 12 :(得分:3)

如果您使用RecyclerView-23.2.1或更高版本。以下解决方案将正常工作:

在您的布局中添加RecyclerView,如下所示:

<android.support.v7.widget.RecyclerView
        android:id="@+id/review_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="vertical" />

在你的java文件中:

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()));

这里layoutManager.setAutoMeasureEnabled(true);可以解决问题。

查看this issuethis developer blog了解详情。

答案 13 :(得分:2)

如果要在 NestedScrollView 中使用 RecyclerView ,这很简单,只需设置:

RecyclerView

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

  • android:nestedScrollingEnabled =“ false”

  • android:layout_height =“ wrap_content”

  • android:overScrollMode =“ never”

NestedScrollView

  • android:fillViewport =“ true”

这对我来说很有效,您也可以在NestedScrollView中使用许多RecyclerView。

答案 14 :(得分:1)

我必须使用工具栏滚动来实现CoordinatorLayout,它让我整天都在忙着解决这个问题。我完全删除了NestedScrollView。所以我只是在根处使用RelativeLayout。

<?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>

答案 15 :(得分:1)

有很多好的答案。关键是必须将java.lang.NoSuchMethodError: org.apache.http.conn.ssl.SSLConnectionSocketFactory.(Ljavax/net/ssl/SSLContext;Ljavax/net/ssl/HostnameVerifier;)V 设置为nestedScrollingEnabled。如上所述,您可以使用Java代码来完成此操作:

false

但是您也有机会在xml代码(mRecyclerView.setNestedScrollingEnabled(false); )中设置相同的属性:

android:nestedScrollingEnabled="false"

答案 16 :(得分:1)

对于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>

答案 17 :(得分:1)

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"/>

答案 18 :(得分:0)

一种保留recyclerview的回收功能并避免recyclerview加载所有数据的解决方案是在recyclerview本身中设置固定高度。通过这样做,recyclerview仅限于加载,只要它的高度可以显示给用户,就可以在滚动到底部/顶部时回收其元素。

答案 19 :(得分:0)

如果您在 NestedScrollView 中使用 RecyclerView ScrollListener ,则同时使用addOnScrollListener侦听器将无法正常工作。

使用此代码。

<div class="sbp-item12">
  <a href="#">
    <div class="bottom-left">
      <h3>Here is a headline</h3>
    </div>
    <figure>
      <img src="https://placehold.it/380x250" alt="Here is a headline" />
    </figure>
  </a>
</div>

此代码在 NestedScrollView 内的 RecyclerView ScrollListener 正常工作。

谢谢

答案 20 :(得分:0)

请勿在NestedScrollView中使用recyclerView。可能会导致级联问题! 我建议在RecyclerView中使用ItemViewTypes处理多种视图。 只需添加一个具有match_parent宽度和高度的RecyclerView。然后在您的recyclerViewAdapter中重写getItemViewType并使用position来处理要放大的布局。之后,您可以使用onBindViewHolder方法处理视图持有人。

答案 21 :(得分:0)

我使用了这个很棒的扩展(用kotlin编写,但也可以用Java编写)

https://github.com/Widgetlabs/expedition-nestedscrollview

基本上,您可以在任何包中放入NestedRecyclerView,让您在项目中说出utils,然后像这样创建recyclerview

 <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

答案 22 :(得分:0)

就我而言,NestedScrollview的子级是ConstraintLayout。它没有按预期工作,我将其替换为LinearLayout。也许对某人有帮助。

<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>

答案 23 :(得分:0)

就我而言,这就是对我有用的

  • android:fillViewport="true"放在NestedScrollView内。

  • 将RecyclerView的高度设置为wrap_content,即android:layout_height="wrap_content"

  • 在RecyclerView android:nestedScrollingEnabled="false"

    中添加它

OR

以编程方式,在您的Kotlin课堂中

recyclerView.isNestedScrollingEnabled = false

mRecyclerView.setHasFixedSize(false)

答案 24 :(得分:0)

至少早在Material Components 1.3.0-alpha03之前,是否嵌套了RecyclerView(在ScrollView或NestedScrollView之外的其他形式)都没有关系。只需将app:layout_behavior="@string/appbar_scrolling_view_behavior"放在其顶层父级中即可,它是CoordinatorLayout中AppBarLayout的同级。

当我将单个Activity架构与Jetpack Naviagation一起使用时,这对我一直有效,其中所有Fragment都从Activity的布局共享相同的AppBar。我将FragmentContainer设为CoordinatorLayout的直接子级,其中也包含AppBarLayout,如下所示。各个片段中的RecyclerViews正常滚动,并且AppBar可以折叠并重新出现。

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:id="@+id/coordinatorLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.fragment.app.FragmentContainerView
            android:id="@+id/nav_host_fragment"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            app:defaultNavHost="true"
            app:navGraph="@navigation/mobile_navigation"/>

        <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/appbar_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:liftOnScroll="true">

            <androidx.appcompat.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:minHeight="?attr/actionBarSize"
                android:theme="?attr/actionBarTheme"
                app:layout_scrollFlags="scroll|enterAlways|snap" />

        </com.google.android.material.appbar.AppBarLayout>

    </androidx.coordinatorlayout.widget.CoordinatorLayout>
如果每个片段将其RecyclerView的ID传递给{{1}中的liftOnScroll,则

AppBarLayout.liftOnScrollTargetViewId(用于使应用栏在页面顶部看起来高度为零)起作用}。如果片段不滚动,则传递0。

答案 25 :(得分:-5)

使用NestedScrollView的
    <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" />