How to enable the default animation on a RecyclerView when an item is added or deleted?

By | May 29, 2017

You may be knowing that RecyclerView is part of the material design, so it will have the built in animations when you add an element or remove and element.
In today’s article, I will show you how to how to do this in a simple way.

RecyclerView will perform a relevant animation if any of the “notify” methods are used except for notifyDataSetChanged; this includes notifyItemChanged, notifyItemInserted, notifyItemMoved, notifyItemRemoved, etc.

Checkout the below example.

The adapter should extend this class instead of RecyclerView.Adapter.

Source Code

import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;

import java.util.List;

public abstract class AnimatedRecyclerAdapter<T, VH extends RecyclerView.ViewHolder>
        extends RecyclerView.Adapter<VH> {

    protected List<T> models;
            
    protected AnimatedRecyclerAdapter(@NonNull List<T> models) {
        this.models = models;
    }

    //Set new models.
    public void setModels(@NonNull final List<T> models) {
        applyAndAnimateRemovals(models);
        applyAndAnimateAdditions(models);
        applyAndAnimateMovedItems(models);
    }

    //Remove an item at position and notify changes.
    private T removeItem(int position) {
        final T model = models.remove(position);
        notifyItemRemoved(position);
        return model;
    }

    //Add an item at position and notify changes.
    private void addItem(int position, T model) {
        models.add(position, model);
        notifyItemInserted(position);
    }

    //Move an item at fromPosition to toPosition and notify changes.
    private void moveItem(int fromPosition, int toPosition) {
        final T model = models.remove(fromPosition);
        models.add(toPosition, model);
        notifyItemMoved(fromPosition, toPosition);
    }

    //Remove items that no longer exist in the new models.
    private void applyAndAnimateRemovals(@NonNull final List<T> newTs) {
        for (int i = models.size() - 1; i >= 0; i--) {
            final T model = models.get(i);
            if (!newTs.contains(model)) {
                removeItem(i);
            }
        }
    }

    //Add items that do not exist in the old models.
    private void applyAndAnimateAdditions(@NonNull final List<T> newTs) {
        for (int i = 0, count = newTs.size(); i < count; i++) {
            final T model = newTs.get(i);
            if (!models.contains(model)) {
                addItem(i, model);
            }
        }
    }

    //Move items that have changed their position.
    private void applyAndAnimateMovedItems(@NonNull final List<T> newTs) {
        for (int toPosition = newTs.size() - 1; toPosition >= 0; toPosition--) {
            final T model = newTs.get(toPosition);
            final int fromPosition = models.indexOf(model);
            if (fromPosition >= 0 && fromPosition != toPosition) {
                moveItem(fromPosition, toPosition);
            }
        }
    }
}

You should NOT use the same List for setModels and List in the adapter.
You declare models as global variables. DataModel is a dummy class only.

Implementation

private List<DataModel> models;
private YourAdapter adapter;

Initialize models before pass it to adapter. YourAdapter is the implementation of AnimatedRecyclerAdapter.


   models = new ArrayList<>();
   //Add models
   models.add(new DataModel());
   //Do NOT pass the models directly. Otherwise, when you modify global models, 
   //you will also modify models in adapter.
   //adapter = new YourAdapter(models); <- This is wrong.
   adapter = new YourAdapter(new ArrayList(models));

   //Call this after you have updated your global models.

   adapter.setModels(new ArrayList(models));

Try these and you will see the animations be default.

Leave your valuable comments below this post.

One thought on “How to enable the default animation on a RecyclerView when an item is added or deleted?

Leave a Reply

Your email address will not be published. Required fields are marked *