在RecyclerView的ItemAnimator上禁用onChange动画 [英] Disable onChange animations on ItemAnimator for RecyclerView

查看:402
本文介绍了在RecyclerView的ItemAnimator上禁用onChange动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用RecyclerView,并使用SortedListAdapterCallbackSortedList获得数据.我想为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.

我尝试查看实现,如果supportsChangeAnimationstrue,则RecyclerView会通过保留旧的viewHolder并将其交叉淡入新的viewHolder中来为更改事件设置动画.我不要如果supportsChangeAnimationsfalse,则旧的和新的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的代码执行文本搜索,发现没有查询mSupportsChangeAnimationsgetSupportsChangeAnimations()-> 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆