如何在notifyItemChanged(pos)之后阻止RecyclerView项目闪烁?

por*_*der 25 android android-recyclerview

我目前有一个回收站视图,其数据每5秒更新一次.要更新列表中的数据,我正在使用

notifyItemChanged(position);
notifyItemRangeChanged(position, mList.size());
Run Code Online (Sandbox Code Playgroud)

每次我调用notifyItemChanged()时,我的recycler视图上的项都会正确更新,但是它会闪烁,因为这会导致再次调用onBindViewHolder.因此,每次都是新鲜的负载.如果可能的话,我怎样才能防止这种情况发生?

Nic*_*oso 55

RecyclerView内置了动画,通常可以添加漂亮的抛光效果.在您的情况下,您将要禁用它们:

((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
Run Code Online (Sandbox Code Playgroud)

(默认的回收器视图动画器应该已经是SimpleItemAnimator的一个实例)

  • 但我认为这也会禁用notifyItemInserted等方法的默认动画 (3认同)

小智 22

您可以禁用项目动画.

mRecyclerView.setItemAnimator(null);
Run Code Online (Sandbox Code Playgroud)

  • 这似乎使 flickr 比以前更快,我正在使用数据绑定。StableIds 是明智的优化,但您在正在更新的行上仍然有 flickr(它们有可以更改状态的单选按钮,但视图的其余部分未更改,因此不应 filckr) (5认同)

Mar*_*och 16

问题可能不是来自动画,而是来自列表项的不稳定 id。

要使用稳定的 ID,您需要:

- setHasStableIds(true)
在 RecyclerView.Adapter 中,我们需要设置 setHasStableIds(true);true 表示此适配器将发布唯一值作为数据集中项目的键。Adapter 可以在通知数据更改后使用该密钥来指示它们是否相同。

- 覆盖 getItemId(int position)
然后我们必须覆盖 getItemId(int position),以返回位置处项目的标识长度。我们需要确保没有具有相同返回 id 的不同项目数据。

解决方案的来源是here。

  • 这应该是公认的答案。setAnimator 为 null 是一个修补程序,不适用于那些想要在其 RecyclerView @portfoliobuilder 中使用动画的人 (4认同)

ros*_*suh 9

如果你想保留RecyclerView的动画并同时避免item闪烁,可以按照以下步骤操作:

1. 直接改变视图组件状态 2. 直接改变Adapter中的数据 3. 不需要通过调用手动刷新UInotifyItemChanged()

直接改变视图并不会立即改变,更好的方法是使用payload来做到这一点。

在您的适配器中:

override fun onBindViewHolder(
        holder: RecyclerView.ViewHolder,
        position: Int,
        payloads: MutableList<Any>
    ) {
        // Using payload to refresh partly
        if (payloads.isNullOrEmpty()) {
            // refresh all 
            onBindViewHolder(holder, position)
            return
        }
        // just change one component's status which would not "flash".
        (holder as YourHolder).apply{
            // make you view change
            // etc. checkBox.isChecked = true
        }
    }
Run Code Online (Sandbox Code Playgroud)

并使用它:


yourAdapter.notifyItemChanged(position, "sample_pay_load")

Run Code Online (Sandbox Code Playgroud)

这是notifyitemchanged 的​​文档


小智 7

在您的适配器中使用 stableId。

调用adapter.setHasStableIds(true)并重写getItemId(int position)适配器类中的方法。

另外,为每个项目返回一些唯一的 ID getItemId(int position)。不要只是简单地返回位置。

  • 没有为我改变任何东西。当用按钮更新一项时,该项仍然闪烁 (7认同)

tir*_*r38 5

发生这种情况是因为 Adapter 正在创建新的 ViewHolder 并尝试在新旧 ViewHolder 之间设置动画。这就是为什么所有“禁用动画”答案在技术上都有效。

相反,您只需告诉RecyclerView重新使用 Viewholders即可canReuseUpdatedViewHolder()。请参阅类似问题的答案: /sf/answers/4229937351/