RecyclerView嵌套在NestedScrollView中时分页无法正常工作

28
如何在嵌套的 NestedScrollView 内实现 recyclerview 的分页?

我尝试实现recyclerview的addOnScrollListener,但它每次绑定数据到recyclerview时都会调用。它应该只在页面末尾调用。 - Jatin
4个回答

56

按照以下步骤操作:

1. 将RecyclerView的“嵌套滚动”功能设置为false。

recyclerView.setNestedScrollingEnabled(false);

2. 给嵌套的滚动视图添加滚动监听器。

 mScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
           @Override
           public void onScrollChanged()
           {
                    View view = (View)mScrollView.getChildAt(mScrollView.getChildCount() - 1);

                    int diff = (view.getBottom() - (mScrollView.getHeight() + mScrollView
                                    .getScrollY()));

                    if (diff == 0) {
                       // your pagination code
                    }
           }
  });

10
它在一次性调用所有分页。 - Eldhopj
嗨@user2162130,您禁用了RecyclerView的滚动吗?这可能发生在存在多个滚动视图时。您需要禁用RecyclerView的滚动。 - Vidhi Dave
@VishvaDave 是的,我已经禁用了recyclerview的滚动,但之后recycler view变得更加沉重和延迟。有时应用程序也因此崩溃。 - user2162130
@user2162130 这是一个奇怪的问题。因为在ScrollView中使用RecyclerView时,这是唯一的解决方案。可能是因为您的RecyclerView正在执行某些操作,例如定时器或循环以呈现数据。如果没有得到适当的管理,则可能会变得很重,除此之外,可以尝试从Java文件和XML中都将嵌套滚动启用设置为false。 - Vidhi Dave
@VishvaDave 如果我移除嵌套滚动视图,那么我的RecyclerView就能正常工作,没有任何卡顿,运行流畅。但是如果我在嵌套滚动视图中使用同样的RecyclerView,那么它会变得很卡顿、很重,并且一段时间后会崩溃。我已经从Java和XML文件中都将嵌套滚动设置为false。 - user2162130
显示剩余3条评论

9

如果您正在使用Kotlin,则您的代码将如下所示:

 scroll?.viewTreeObserver?.addOnScrollChangedListener {
        val view = scroll.getChildAt(scroll.childCount - 1)
        Timber.d("Count==============${scroll.childCount}")

        val diff = view.bottom - (scroll.height + scroll.scrollY)
        Timber.d("diff==============$diff")

        if (diff == 0) {
            //your api call to fetch data
        }
    }

最后但并非最不重要的,将RecyclerView的滚动设置为false

 ViewCompat.setNestedScrollingEnabled(recyclerView, false)

这对我不起作用,有人能帮忙吗? - Srishti Roy
@SrishtiRoy 你尝试过将RecyclerView的滚动设置为false吗? - Shreyash Mahajan

3

我可以通过在nestedScrollView中设置OnScrollChangeListener来获取解决方案。

字段isLoading应该在每次加载项目时更改,例如如果您正在使用Retrofit。您可以在其开始运行时将其设置为true,并在获得responsefailure时将其设置为false

字段isLastPage应该在每次获取项目时更改,并检查是否是最后一页。

我正在使用Kotlin。

private var isLoading = false

private var isLastPage = false

nestedScrollView.setOnScrollChangeListener { v: NestedScrollView?, scrollX: Int, scrollY: Int, oldScrollX: Int, oldScrollY: Int ->

            val nestedScrollView = checkNotNull(v){
                return@setOnScrollChangeListener
            }

            val lastChild = nestedScrollView.getChildAt(nestedScrollView.childCount - 1)

            if (lastChild != null) {

                if ((scrollY >= (lastChild.measuredHeight - nestedScrollView.measuredHeight)) && scrollY > oldScrollY && !isLoading && !isLastPage) {

                    //get more items
                }
            }
        }

当然,你需要将字段 isNestedScrollingEnabled 设置为 false

myRecyclerView.isNestedScrollingEnabled = false

0

我曾经遇到过同样的问题,根据 Android 文档:

永远不要将 RecyclerView 或 ListView 添加到滚动视图中。这样做会导致用户界面性能差和用户体验差。

我使用下面的代码解决了我的问题:

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

<com.google.android.material.appbar.AppBarLayout
    android:id="@+id/appbar_layout"
    android:background="@color/white"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <com.google.android.material.appbar.CollapsingToolbarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_scrollFlags="scroll|exitUntilCollapsed"
        app:titleEnabled="false">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <!-- Put here elements that you need above the recycler view -->

        </LinearLayout>

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

</com.google.android.material.appbar.AppBarLayout>
<!-- RecyclerView -->
<androidx.recyclerview.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:nestedScrollingEnabled="true"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    android:scrollbars="vertical"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

如果在AppBarLayout下面有一个TabLayout,并且TabLayout中可能有两个具有RecyclerView的不同Fragment,那么这段代码就会失效。因此,这不是一个有效的解决方案。 - Kishan Solanki
它的工作非常糟糕,而且你无法将所有内容都包含在下拉刷新视图中。 - user924

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接