调用 notifydatasetchanged 后 Recyclerview 滚动到顶部

Posted

技术标签:

【中文标题】调用 notifydatasetchanged 后 Recyclerview 滚动到顶部【英文标题】:Recyclerview scrolling to top after calling notifydatasetchanged 【发布时间】:2016-02-10 02:38:29 【问题描述】:

我有一个水平 recyclerview(带有一个 LinearLayoutManager),它的子项有一个包含在 relativelayout 中的 imageview。 recyclerview 具有三个包含子项的水平行。当 recyclerview 滚动时,我正在使用来自 http 调用的响应更新数据集,并在 http 响应回调中调用 notifydatasetChanged。如果 recyclerview 子项的高度和宽度是固定值(例如 150dp、84dp),则 recyclerview 的行为符合预期,即加载新项目并保持在相同的滚动位置,但如果我将 recyclerview 子项的高度和宽度设置为 match_parent 和wrap_content,recyclerview 完全刷新并滚动到第一个位置。为什么会这样? 注意:我已经检查了其他类似的关于 SO 的问题,但没有一个提供可行的解决方案。

main_layout

<android.support.v7.widget.RecyclerView
    android:id="@+id/grid_recycler_view"
    android:layout_
    android:layout_
    android:layout_marginBottom="110dp"
    android:layout_marginLeft="15dp"
    android:layout_marginTop="80dp"
    android:background="@color/transparent"
    android:outlineProvider="bounds"
    android:elevation="8dp"
    android:padding="0dp"
    android:scrollbars="none" />
....

recycler_view_child_item

<RelativeLayout      xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:orientation="vertical"
android:padding="0dp">
<ImageView
    android:id="@+id/thumbnail"
    android:layout_
    android:layout_
    android:adjustViewBounds="true"
    android:maxWidth="126dp"
    android:maxHeight="225dp"
    android:padding="0dp"/>
</RelativeLayout>

【问题讨论】:

你找到解决办法了吗? 【参考方案1】:

我遇到了同样的问题,也找不到关于 SO 的解决方案。该问题是由于没有为RecyclerView 设置LayoutManager 引起的。我知道你说你有一个LinearLayoutManager。但请确保您已按以下方式进行设置。 (就我而言,我使用的是HorizontalGridView,但同样的原则也适用于RecyclerView)。

horizontalGridView = (HorizontalGridView) findViewById(R.id.gridView);
GridElementAdapter adapter = newGridElementAdapter(VenueProfileActivity.this, mDeals);
horizontalGridView.setAdapter(adapter);

HorizontalGridView.LayoutManager layoutManager = new LinearLayoutManager(VenueProfileActivity.this, LinearLayoutManager.HORIZONTAL, false);
horizontalGridView.setLayoutManager(layoutManager);
horizontalGridView.setHasFixedSize(true);

【讨论】:

【参考方案2】:

刷新可能是因为您没有指定子视图的大小。我要做的第一件事是删除减少视图深度的RelativeLayout,因为它似乎没有任何用途。此外,如果 recyclerView 的子视图的大小始终相同,请将其设置在 childViews 本身而不是 parentView aka recyclerView 上。你在 recyclerView 上也将HasFixedSize 设置为 true 吗?

【讨论】:

删除了相对布局。因为我正在设置 recyclerview 的大小以匹配父级的大小和一些边距,所以回收器视图的大小可能因设备而异。所以我不能为子视图设置固定大小。回收器视图有三行,因此我设置了子视图的高度以匹配父视图和宽度以包装内容以避免回收器视图中子视图之间的任何空格。 另外,我已将 setHasFixedSize 设置为 true。【参考方案3】:

我遇到了同样的问题,发现 mossy321 的答案很有用,但并没有为我解决所有问题。在我的应用程序中,我有一个对象列表,每个对象都有一个时间,需要每 30 秒左右递增一次。我在托管片段中运行了一个计时器,但更新数据导致了跳跃问题。

我的回收站代码如下:

 orderRecycler = (RecyclerView) rootView.findViewById(R.id.order_recycler_view);
    // use this setting to improve performance if you know that changes
    // in content do not change the layout size of the RecyclerView
    orderRecycler.setHasFixedSize(true);

    //Stops items doing a default flashing animation on individual refresh
    RecyclerView.ItemAnimator animator = orderRecycler.getItemAnimator();
    if (animator instanceof SimpleItemAnimator) 
        ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
    

    orderLayoutManager = new LinearLayoutManager(getActivity());
    orderRecycler.setLayoutManager(orderLayoutManager);
    orderAdapter = new OrderAdapter(orderArrayList, historyArrayList, getActivity());

    orderRecycler.setAdapter(orderAdapter);

这里需要注意的是 setHasFixedSize 很关键。我猜在数据更改时,系统必须重新绘制视图以强制跳转到顶部问题,但如果它知道它们将具有相同的大小,它可以在这种情况下更新更改的文本。

另一个问题是我不能使用 notifyDatasetChanged 或者它仍然会导致同样的问题。我必须单独通知每个项目。这就是项目动画师在回收站声明中的用途。否则,项目将在更新时闪烁。

 for(int i = 0; i < orderArrayList.size(); i++)
                orderAdapter.notifyItemChanged(i);
            

【讨论】:

【参考方案4】:

您可以在调用 notifyDataSetChanged 时将 RecyclerView 滚动到特定位置

recyclerView.scrollToPosition(array.size() - 1);

【讨论】:

以上是关于调用 notifydatasetchanged 后 Recyclerview 滚动到顶部的主要内容,如果未能解决你的问题,请参考以下文章

在 RecyclerView 的第一个索引处添加项目并调用 notifydatasetchange 后如何保持在滚动位置

RecyclerView notifyDataSetChanged不起作用

notifyDataSetChanged 后如何避免闪烁效果

ViewPager 调用notifyDataSetChanged()不刷新内容的问题

在 notifyDataSetChanged 上未调用 GetView,ListView 卡住

每当在 recyclerview 中为 base64 图像调用 notifydatasetchanged() 时,图像就会闪烁