在ItemAnimator上为RecyclerView禁用onChange动画

JHH*_*JHH 7 android android-support-library android-recyclerview

我使用的是RecyclerView一个SortedList使用a的数据SortedListAdapterCallback.我想禁用onChange事件的动画,但保留它们为onInserted/ onRemoved/ onMoved.我曾尝试调用setSupportsChangeAnimations(false)DefaultItemAnimator使用的RecyclerView,但动画仍然出现.如果我调用setItemAnimator(null) 所有动画都按预期成功删除了.

我试着查看实现,看起来似乎supportsChangeAnimationstrue,RecyclerView通过保持旧的viewHolder并将其交叉淡入到新的viewHolder ,将动画更改事件.我不希望这样.如果supportsChangeAnimationsfalse,新老viewHolders然而,将相同的对象,而且会有替代地是onMoved动画从x到x(即没有实际移动).然而,这意味着该项目将产生令人讨厌的反弹效果.我也不想要那个,我根本不需要动画.:(

来自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);
    }
    ...
Run Code Online (Sandbox Code Playgroud)

有时当我加载我的列表时,我异步地获取一些数据并更新项目1-3次,当它每次都弹跳和闪烁时看起来真的很糟糕.

如何在onChange不诉诸编写完全自定义的ItemAnimator的情况下有效地完全禁用动画?

Den*_*nis 12

我参加这个派对有点晚了,但是使用androidx.recyclerview:recyclerview:1.1.0我可以将默认动画师的更改设置changeDuration为 0,这有效地禁用了动画,同时允许添加/移动/删除动画继续正常运行。不需要自定义覆盖DefaultItemAnimator.

示例(在 Kotlin 中):

view.my_recycler_view.itemAnimator?.changeDuration = 0
Run Code Online (Sandbox Code Playgroud)


cju*_*jiu 9

查看代码(我正在使用支持库25.2.0):setSupportsChangeAnimations(<value>)是抽象类的一个方法SimpleItemAnimator,它也是DefaultItemAnimator超类.在内部,它修改了值mSupportsChangeAnimations.

DefaultItemAnimator代码中执行文本搜索,显示既没有mSupportsChangeAnimations,也没有getSupportsChangeAnimations()查询 - > DefaultItemAnimator字面上忽略了这个标志.

正确的解决方案是以DefaultItemAnimator下列方式扩展:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

查看文档animateChange(...)以了解dispatchChangeFinished(...)在没有运行动画时需要调用的原因.

当没有动画可以运行时,可能有一种更优雅的方式来编写else分支,但是唉,这实现了所需的行为.

有点晚了,但希望这有帮助!


Dav*_*ung 6

上面的解决方案不适用于支持库版本25.3.1的我,因为我想禁用所有回收者视图项目的动画。我通过重写解决了它SimpleItemAnimator

private class NoAnimationItemAnimator extends SimpleItemAnimator {
    @Override
    public boolean animateRemove(RecyclerView.ViewHolder holder) {
        dispatchRemoveFinished(holder);

        return false;
    }

    @Override
    public boolean animateAdd(RecyclerView.ViewHolder holder) {
        dispatchAddFinished(holder);

        return false;
    }

    @Override
    public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) {
        dispatchMoveFinished(holder);

        return false;
    }

    @Override
    public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
        dispatchChangeFinished(oldHolder, true);
        dispatchChangeFinished(newHolder, false);

        return false;
    }

    @Override
    public void runPendingAnimations() {
        // stub
    }

    @Override
    public void endAnimation(RecyclerView.ViewHolder item) {
        // stub
    }

    @Override
    public void endAnimations() {
        // stub
    }

    @Override
    public boolean isRunning() {
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 好吧,它可能会起作用,但是问题与仅禁用 onChange 和保留其他动画严格相关 (2认同)