Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No animation on item removal on RecyclerView

I am using RecyclerView for the first time. Everything is working fine except that there is no animation on item removal even though the animation on item addition works just fine.

I have not set any custom item animator, but according to the documentation:

Animations for adding and removing items are enabled by default in RecyclerView.

So the animations on removal should work.

I would like to have the default animation on removal, but can't get that to work.

This is how I setup the RecyclerView:

private void setupRecyclerView() {
  mRecyclerView = (RecyclerView) mRootView.findViewById(R.id.recycler_view);
  mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
  View emptyView = mRootView.findViewById(R.id.empty_view);
  mAdapter = new RoutineAdapter(getActivity(), mRoutineItems, emptyView);
  mRecyclerView.setAdapter(mAdapter);
}

This is my adapter:

private class RoutineAdapter
      extends RecyclerView.Adapter<RoutineAdapter.ViewHolder> {

private final Context mContext;
private List<RoutineItem> mData;
private View mEmptyView;

    public RoutineAdapter(Context context, List<RoutineItem> data, View emptyView) {
      mContext = context;
      mData = data;
      mEmptyView = emptyView;
      setEmptyViewVisibility();
    }

    public void add(RoutineItem routineItem, int position) {
      mData.add(position, routineItem);
      setEmptyViewVisibility();
      notifyItemInserted(position);
    }

    public void remove(int position){
      mData.remove(position);
      setEmptyViewVisibility();
      notifyItemRemoved(position);
    }

    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
      final View view = LayoutInflater.from(mContext).inflate(
          R.layout.fragment_routines_list_item, parent, false);
      return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
      final RoutineItem routineItem = getItem(position);
      holder.circle.setBackgroundResource(
          colorNumberToDrawableResource(routineItem.colorNumber));
      holder.initial.setText(routineItem.routineName.substring(0, 1));
      holder.routineName.setText(routineItem.routineName);
      holder.lastTimeDone.setText(routineItem.lastTimeDoneText);
      if (routineItem.isSelected) {
        holder.itemView.setBackgroundColor(
            getResources().getColor(R.color.background_item_selected));
      } else {
        holder.itemView.setBackgroundResource(
            R.drawable.darker_background_on_pressed);
      }
      holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
          mPresenter.onRoutineClicked(routineItem.routineName);
        }
      });
      holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
          mPresenter.onRoutineLongClicked(routineItem.routineName);
          return true;
        }
      });
    }

    @Override
    public int getItemCount() {
      return mData.size();
    }

    public RoutineItem getItem(int position) {
      return mData.get(position);
    }

    private void setEmptyViewVisibility() {
      if (getItemCount() == 0) {
        mEmptyView.setVisibility(View.VISIBLE);
      } else {
        mEmptyView.setVisibility(View.GONE);
      }
    }

    class ViewHolder extends RecyclerView.ViewHolder {
      public final View circle;
      public final TextView initial;
      public final TextView routineName;
      public final TextView lastTimeDone;

      public ViewHolder(View view) {
        super(view);
        circle = view.findViewById(R.id.circle);
        initial = (TextView) view.findViewById(R.id.initial);
        routineName = (TextView) view.findViewById(R.id.routine_name);
        lastTimeDone = (TextView) view.findViewById(R.id.last_time_done);
      }
    }
}

Fragment_routines_list_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:minHeight="@dimen/standard_list_item_height"
  android:paddingBottom="8dp"
  android:background="@drawable/darker_background_on_pressed"
  android:clickable="true">
    ......
</RelativeLayout>

What am I doing wrong that causes the default removal animation to not work?

like image 207
Jordi Chacón Avatar asked Nov 28 '14 11:11

Jordi Chacón


3 Answers

The proper way to remove an item from recycler view is to remove the item from data set and then telling the adapter that the item is removed like so

myDataset.remove(position); // myDataset is List<MyObject>
mAdapter.notifyItemRemoved(position);
like image 81
Much Overflow Avatar answered Nov 15 '22 21:11

Much Overflow


Solved it.

The issue was that, after calling mAdapter.remove(position), another part of my code was calling mAdapter.notifyDataSetChanged() which I assume stops the removal animation.

To sum up, if you call mAdapter.notifyDataSetChanged while there is an animation ongoing the animation will stop.

like image 38
Jordi Chacón Avatar answered Nov 15 '22 22:11

Jordi Chacón


Use notifyItemRemoved(position) instead of notifyDataSetChanged() like below

myDataset.remove(position);
notifyItemRemoved(position);

because notifyDataSetChanged() simply notifies the updated data without any animations.

like image 14
Praveen Balaji Avatar answered Nov 15 '22 23:11

Praveen Balaji