在RecyclerView的ItemAnimator上禁用onChange动画 [英] Disable onChange animations on ItemAnimator for RecyclerView
问题描述
我正在使用RecyclerView
,并使用SortedListAdapterCallback
从SortedList
获得数据.我想为onChange
事件禁用动画,但为onInserted
/onRemoved
/onMoved
保留动画.我尝试在RecyclerView
使用的DefaultItemAnimator
上调用setSupportsChangeAnimations(false)
,但是动画仍然出现.如果我拨打setItemAnimator(null)
所有动画,将按预期成功删除.
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(<value>)
是抽象类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()
-> 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屋!