为 RecyclerView 禁用 ItemAnimator 上的 onChange 动画 [英] Disable onChange animations on ItemAnimator for RecyclerView
问题描述
我正在使用 RecyclerView
提供来自 SortedList
的数据,使用 SortedListAdapterCallback
.我想为 onChange
事件禁用动画,但为 onInserted
/onRemoved
/onMoved
保留它们.我尝试在 RecyclerView
使用的 DefaultItemAnimator
上调用 setSupportsChangeAnimations(false)
,但动画仍然出现.如果我调用 setItemAnimator(null)
all 动画会按预期成功删除.
I am using a RecyclerView
fed with data from a SortedList
using a SortedListAdapterCallback
. I want to disable animations for onChange
events, but preserve them for onInserted
/onRemoved
/onMoved
. I have tried calling setSupportsChangeAnimations(false)
on the DefaultItemAnimator
used by the RecyclerView
, but the animation still appears. If I call setItemAnimator(null)
all animations are successfully removed as expected though.
我尝试查看实现,似乎如果 supportsChangeAnimations
是 true
,RecyclerView
将通过保留旧的 viewHolder 来动画更改事件并将其淡入淡出到新的 viewHolder.我不想要那个.如果 supportsChangeAnimations
是 false
,那么旧的和新的 viewHolders 将是同一个对象,而是会有一个从 x 到 x 的 onMoved
动画(即,没有实际移动).然而,这意味着该项目将获得令人讨厌的反弹效果.我也不想要那个,我根本不想要动画.:(
I tried looking at the implementation and it seems like if supportsChangeAnimations
is true
, the RecyclerView
will animate change events by keeping the old viewHolder and cross-fade it to the new viewHolder. I don't want that. If supportsChangeAnimations
is false
, the old and new viewHolders will however be the same object, and there will instead be an onMoved
animation from x to x (i.e., no actual move). This however means that the item will get an annoying bounce effect. I don't want that either, I want no animation at all. :(
来自 DefaultItemAnimator.java:
From DefaultItemAnimator.java:
@Override
public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder,
int fromX, int fromY, int toX, int toY) {
if (oldHolder == newHolder) {
// Don't know how to run change animations when the same view holder is re-used.
// run a move animation to handle position changes.
return animateMove(oldHolder, fromX, fromY, toX, toY);
}
...
有时当我加载我的列表时,我会异步获取一些数据并更新项目 1-3 次,而且每次都弹跳和闪烁时看起来真的很糟糕.
Sometimes when I load my list I asynchronously fetch some data and update items 1-3 times, and it looks really crappy when it bounces and flickers every time.
如何有效地完全禁用 onChange
动画而不求助于编写完全自定义的 ItemAnimator?
How do I effectively completely disable onChange
animations without resorting to writing a completely custom ItemAnimator?
推荐答案
看代码(我用的是支持库25.2.0):setSupportsChangeAnimations(
是一个方法在抽象类 SimpleItemAnimator
上,它也是 DefaultItemAnimator
的超类.在内部,它会修改 mSupportsChangeAnimations
的值.
Looking through the code (I'm using support library 25.2.0): setSupportsChangeAnimations(<value>)
is a method on the abstract class SimpleItemAnimator
, which is also DefaultItemAnimator
's superclass. Internally, it modifies the value of mSupportsChangeAnimations
.
在 DefaultItemAnimator
的代码中执行文本搜索,发现 mSupportsChangeAnimations
和 getSupportsChangeAnimations()
都没有被查询 -->code>DefaultItemAnimator 从字面上忽略这个标志.
Performing a text search in DefaultItemAnimator
's code, reveals that neither mSupportsChangeAnimations
, nor getSupportsChangeAnimations()
are queried --> the DefaultItemAnimator
literally ignores this flag.
正确的解决方案是按以下方式扩展DefaultItemAnimator
:
The correct solution is to extend the DefaultItemAnimator
in the following manner:
public class CustomItemAnimator extends DefaultItemAnimator {
@Override
public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
if (getSupportsChangeAnimations()) {
return super.animateChange(oldHolder, newHolder, fromX, fromY, toX, toY);
} else {
if (oldHolder == newHolder) {
if (oldHolder != null) {
//if the two holders are equal, call dispatch change only once
dispatchChangeFinished(oldHolder, /*ignored*/true);
}
} else {
//else call dispatch change once for every non-null holder
if (oldHolder != null) {
dispatchChangeFinished(oldHolder, true);
}
if (newHolder != null) {
dispatchChangeFinished(newHolder, false);
}
}
//we don't need a call to requestPendingTransactions after this, return false.
return false;
}
}
请参阅文档 animateChange(...)
以了解为什么在没有运行动画时需要调用 dispatchChangeFinished(...)
.
See docs animateChange(...)
to understand why it was needed to call dispatchChangeFinished(...)
when no animations were run.
当没有要运行的动画时,可能有一种更优雅的方式来编写 else 分支,但可惜,这实现了所需的行为.
Probably there's a more elegant way to write the else branch when there are no animations to be run, but alas, this achieves the desired behavior.
有点晚了,但希望这会有所帮助!
Kind'of late, but hope this helps!
这篇关于为 RecyclerView 禁用 ItemAnimator 上的 onChange 动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!