Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
371 views
in Technique[技术] by (71.8m points)

android - Disable onChange animations on ItemAnimator for RecyclerView

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.

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. :(

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);
    }
    ...

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.

How do I effectively completely disable onChange animations without resorting to writing a completely custom ItemAnimator?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.

Performing a text search in DefaultItemAnimator's code, reveals that neither mSupportsChangeAnimations, nor getSupportsChangeAnimations() are queried --> the DefaultItemAnimator literally ignores this flag.

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;
    }
}

See docs animateChange(...) to understand why it was needed to call dispatchChangeFinished(...) when no animations were run.

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!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...