ScrollView/NestedScrollView 中的 RecyclerView 滚动不流畅

9
我有一个布局,其中包含一个 CardView 和一个与之关联的 FloatingActionButton。在 CardView 下方有一系列回复(即 RecyclerView)。有时候 CardView 的高度大于屏幕,因此我使用了 layout_height="wrap_content" 来设置 CardView 的高度,并将整个 LinearLayout 包装在一个 ScrollView 中。

然而,这会引起一个问题(因为它是一个嵌套在 ScrollView 中的滚动视图),当滚动 RecyclerView 的项目时。根据一些问题回答的建议,我已经使用了 NestedScrollViewandroid:nestedScrollingEnabled="true" 标签,但是在 RecyclerView 中的滚动仍然存在问题。

这是我的 Layout 文件 -

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.forum.reply.ReplyActivity">

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

        <android.support.v7.widget.Toolbar
            android:id="@+id/reply_toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="?attr/colorPrimary"
            android:minHeight="?attr/actionBarSize"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:titleTextColor="@android:color/white"/>

        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:nestedScrollingEnabled="true"
            android:fillViewport="true">

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

                <android.support.v7.widget.CardView
                    android:id="@+id/topic_card"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:paddingBottom="@dimen/card_margin"
                    android:paddingLeft="@dimen/card_margin"
                    android:paddingRight="@dimen/card_margin"
                    android:paddingTop="@dimen/card_margin">

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="vertical"
                        android:paddingEnd="@dimen/card_margin"
                        android:paddingStart="@dimen/card_margin">

                        <android.support.v7.widget.AppCompatTextView
                            android:id="@+id/topic_title"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="8dp"
                            android:layout_marginTop="8dp"
                            android:textAppearance="@style/TextAppearance.AppCompat.Title"/>

                        <android.support.v7.widget.AppCompatTextView
                            android:id="@+id/topic_content"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:textAppearance="@style/TextAppearance.AppCompat.Body1"/>
                    </LinearLayout>
                </android.support.v7.widget.CardView>

                <ProgressBar
                    android:id="@+id/reply_progressbar"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:indeterminate="true"
                    android:visibility="visible"/>

                <android.support.v7.widget.RecyclerView
                    android:id="@+id/list_of_replies"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:visibility="invisible"/>
            </LinearLayout>
        </ScrollView>
    </LinearLayout>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/reply_to_topic"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:clickable="true"
        android:src="@drawable/ic_reply_white_24dp"
        app:layout_anchor="@id/topic_card"
        app:layout_anchorGravity="bottom|right|end"/>

</android.support.design.widget.CoordinatorLayout>

以下是一些图片 -

可见的带悬浮按钮的CardView

从CardView向Recyclerview滚动很流畅

向下滚动不够流畅

向上滚动也不够流畅

6个回答

29

当您的布局中有多个可滚动视图(如RecyclerView + ScrollView)并且在RecyclerView中滚动时,RecyclerView将随父级ScrollView一起滚动。这会导致RecyclerView中出现抖动。您可以通过以下方式避免此抖动:

您可以在XML中为RecyclerView添加
android:nestedScrollingEnabled="false"或在Java中为RecyclerView添加
recyclerView.setNestedScrollingEnabled(false);


1
你能解释一下这为什么有效吗?另外,我还需要支持API v21以下的设备。 - yadav_vi
2
您的布局中有多个可滚动视图,因此当您在触摸RecyclerView时滚动时,RecyclerView会随着父ScrollView一起滚动。这会导致RecyclerView出现抖动问题。设置nestedScrollingEnabled="false"可以使RecyclerView停止滚动,只有来自父ScrollView的触发滚动效果。此外,使用.setNestScrollingEnabled()进行编程处理,在API版本早于v21的设备上可以正常工作。 - Siddhesh Dighe
1
我已经接受了回答,但你能否在回答中更新你在评论中提到的内容。 - yadav_vi
由于上面的代码,我的最后一个卡片视图被裁剪了。 - Rahul Chaudhary
6
请注意,如果您想支持v21以下的设备,则需要使用ViewCompat.setNestedScrollingEnabled(mRecyclerView, false);。 @yadav_vi - marios-codes

10
如果您要支持API 21以下的设备,则应在您的Activity/Fragment中使用以下代码:ViewCompat.setNestedScrollingEnabled(mRecyclerView, false);

1
请问您能否解释一下为什么我的回答是错误的并且被踩了吗?我想知道是否我犯了错误,因为我在我的代码中使用了上面的片段,而且它运行得很好。谢谢。 - marios-codes

3
您需要完成多个任务:
  1. 将您的RecyclerView放置在android.support.v4.widget.NestedScrollView中,而不是普通的ScrollView
  2. 在布局XML文件中设置您的RecyclerView android:nestedScrollingEnabled="true"
  3. 为了支持API 21以下的设备,您应该在代码中使用ViewCompat.setNestedScrollingEnabled(mRecyclerView, false)
  4. 将您的RecyclerView高度设置为android:layout_height="wrap_content"(如果是横向的,则设置宽度!)

3
除了设置 android:nestedScrollingEnabled="false" 之外,您需要确保 RecyclerView 的父级是 android.support.v4.widget.NestedScrollView
当 RecyclerView 在标准的 ScrollView 中时,在大屏幕上它可能无法正常测量。

1
如果您想在ScrollView中滚动RecyclerView,但是ScrollView会阻止RecyclerView滚动(在API 16中),您应该使用android.support.v4.widget.NestedScrollView而不是ScrollView,并且还必须设置nestedScrollView.setNestedScrollingEnabled(false);这样可以防止在滚动RecyclerView时滚动nestedScrollView。希望这可以帮助某些人。

0
我有一个问题,通过使用自定义ScrollView并覆盖onInterceptTouchEvent方法返回false来解决它。
希望能对某些人有所帮助。

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