68

In my project I need disable the "change" animation of RecyclerView while notifyItemChanged.

I investigated in the source of RecyclerView and had overridden android.support.v7.widget.DefaultItemAnimator as below:

private static  class ItemAnimator extends DefaultItemAnimator
{
    @Override
    public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, int fromX, int fromY, int toX, int toY) {
        if(oldHolder != null)
        {
            oldHolder.itemView.setVisibility(View.INVISIBLE);
            dispatchChangeFinished(oldHolder, true);
        }

        if(newHolder != null)
        {
            dispatchChangeFinished(newHolder, false);
        }

        return false;
    }
}

But I am not sure if I match the spec of the Google document: RecyclerView.ItemAnimator.animateChange

According to my understanding source code, if I do not override the method properly, the oldHolder will not be recycled.

Please help me figure out how to override animateChange in a correct way.

CaptJak
  • 3,592
  • 1
  • 29
  • 50
Kenny
  • 1,901
  • 2
  • 11
  • 8

9 Answers9

122

I have found the correct solution to just remove the animateChange.

It's very simple. Google has implemented the functionality.

((SimpleItemAnimator) RecyclerView.getItemAnimator()).setSupportsChangeAnimations(false);

Documentation: setSupportsChangeAnimations

Vukašin Manojlović
  • 3,717
  • 3
  • 19
  • 31
Kenny
  • 1,901
  • 2
  • 11
  • 8
  • 3
    It's also defined in *DefaultItemAnimator* and you can do it in this way: `((DefaultItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);` – Juan Saravia Jul 28 '16 at 16:03
  • 2
    This broke the item move animations for DiffUtil.Result.dispatchChanges for me. – Mavamaarten May 31 '19 at 06:54
  • @Mavamaarten try `recyclerView.getItemAnimator().setChangeDuration(0)`, work for me. – Sam Chen Nov 25 '20 at 17:30
55

I had the same problem. When calling notifyItemChanged there was a red overlay flashing. After experimenting around with your code I finally removed the default Animator by simply calling

recyclerView.setItemAnimator(null);

on the RecyclerView.

Saenic
  • 1,593
  • 13
  • 14
  • 13
    recyclerView.setItemAnimator(null); Will remove all animation of RecyclerView. I only want to remove animateChange. Thank you for your answer. – Kenny May 15 '15 at 01:29
8

@Kenny answer didn't work anymore because google remove method setSupportsChangeAnimations() (but why?) in support library 23.1.0.

In some case setChangeDuration(0) can work as workaround.

@edit I suggest use something like that:

  RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator();
        if (animator instanceof SimpleItemAnimator) {
            ((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
        }
Shu
  • 277
  • 1
  • 5
  • 14
  • so you basically using the same method after a sugar instanceof ? – narancs Aug 02 '17 at 20:56
  • 1
    At this moment my post no have any sense because Kenny post was edited after i wrote my own. Previous kenny implementation it's not working on 23.1.0+ support library so i paste own solution for it. – Shu Aug 04 '17 at 17:04
  • This method is present in current Support library, see [docs](https://developer.android.com/reference/android/support/v7/widget/SimpleItemAnimator.html#setSupportsChangeAnimations(boolean)). Also, it is present in Android X packages. What are you talking about? – Vadim Kotov Jul 08 '19 at 14:00
8

Just if someone stumbles like me:
Somehow setSupportsChangeAnimations(false) didn't work for me, but recyclerView.getItemAnimator().setChangeDuration(0) has just removed the animation nicely.

Touhid
  • 731
  • 1
  • 10
  • 25
5

If found a solution, for everyone who wants to keep all the animations given by the DefaultItemAnimator, but getting rid of the "blink" animation that occurs every time the view is updated.

First, get the source code of DefaultItemAnimator. Create a class with the same name in your project.

Second, set the ItemAnimator to a new instance of your modified DefaultItemAnimator, like so:

recyclerView.setItemAnimator(new MyItemAnimator());

Then, go in the new classes source code and locate the method

animateChangeImpl(final ChangeInfo changeInfo) { ... }

Now, we simply have to locate the method calls changing alpha values. Find the following two lines and remove the .alpha(0) and .alpha(1)

oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() { ... }
newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()).alpha(1).setListener(new VpaListenerAdapter() { ... }

like so

oldViewAnim.setListener(new VpaListenerAdapter() { ... }
newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()).setListener(new VpaListenerAdapter() { ... }
Alex
  • 1,395
  • 1
  • 13
  • 22
3

The easiest solution is to extend DefaultItemAnimator and set setSupportsChangeAnimations to false right in the constructor:

public class DefaultItemAnimatorNoChange extends DefaultItemAnimator {
    public DefaultItemAnimatorNoChange() {
        setSupportsChangeAnimations(false);
    }
}
rafakob
  • 3,946
  • 3
  • 26
  • 36
2

I've created an Extention Class, to disable animation

import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SimpleItemAnimator

fun RecyclerView.disableAnimation() {
    (itemAnimator as? SimpleItemAnimator)?.supportsChangeAnimations = false
}

You can call it like this:

recyclerView.disableAnimation()
afollestad
  • 2,929
  • 5
  • 30
  • 44
Waqar UlHaq
  • 6,144
  • 2
  • 34
  • 42
1

Here is a simple and an efficient way to do this:

public class NoAnimAnimator extends DefaultItemAnimator {
    public NoAnimAnimator() {
        setSupportsChangeAnimations(false);
        setChangeDuration(0);
    }
}

And in your recyclerview, add the animator:

recylerview.setItemAnimator(new NoAnimAnimator());

Happy Coding!

WebDiva
  • 133
  • 3
  • 23
-1

Nothing of the above solutions worked for me. What worked was using the TransitionManager and setting the scene transition to null

TransitionManager.go(new Scene(recyclerView), null);

To re-enable the default animation you can create a new AutoTransition and set it to the same method above:

AutoTransition autoTransition = new AutoTransition();
TransitionManager.go(new Scene(recyclerView), autoTransition);
Malek Hijazi
  • 4,112
  • 1
  • 26
  • 31