RecyclerView Adapter notifyDataSetChanged stops fancy animation

elgui picture elgui · Dec 4, 2014 · Viewed 31k times · Source

I am building a component based on RecyclerView, allowing user to reorder items by drag and drop. Once I am on the DragListener side, I need the position it has in the adapter in order to perform correct move, but I only have access to the view. So here is what I am doing in the adapter view binding :

@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
    Track track = mArray.get(position);
    viewHolder.itemView.setTag(R.string.TAG_ITEM_POSITION, position);
}

Does it seem correct to you ? Because if I move an item like this :

public void move(int from, int to){
    Track track = mArray.remove(from);
    mArray.add(to, track);
    notifyItemMoved(from, to);
}

then position tag is not correct anymore, and if I notifyDataSetChanged(), I lose the fancy animation. Any suggestion ?

Answer

tochkov picture tochkov · Apr 22, 2015

There is a way to preserve fancy animations with just notifyDataSetChanged()

  1. You need to make your own GridLayoutManager with overriden supportsPredictiveItemAnimations() method returning true;

  2. You need to mAdapter.setHasStableIds(true)

  3. The part I find tricky is you need to override you adapter's getItemId() method. It should return value that is truly unique and not a direct function of position. Something like mItems.get(position).hashCode()

Worked perfectly fine in my case - beautiful animations for adding, removing and moving items only using notifyDataSetChanged()