RecyclerView Adapter notifyDataSetChanged stops fancy animation
Solution 1
No, it is wrong. First of all, you cannot reference to the position passed to the onBindViewHolder after that method returns. RecyclerView will not rebind a view when its position changes (due to items moving etc).
Instead, you can use ViewHolder#getPosition()
which will return you the updated position.
If you fix that, your move code should work & provide nice animations.
Calling notifyDataSetChanged
will prevent predictive animations so avoid it as long as you can. See documentation for details.
Edit (from comment): to get position from the outside, get child view holder from recyclerview and then get position from the vh. See RecyclerView api for details
Solution 2
There is a way to preserve fancy animations with just notifyDataSetChanged()
You need to make your own
GridLayoutManager
with overridensupportsPredictiveItemAnimations()
method returningtrue
;You need to
mAdapter.setHasStableIds(true)
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 ofposition
. Something likemItems.get(position).hashCode()
Worked perfectly fine in my case - beautiful animations for adding, removing and moving items only using notifyDataSetChanged()
Solution 3
1) You'll use notifyItemInserted(position);
or notifyItemRemoved(position);
instead of notifyDataSetChanged()
for animation.
2) You can just manually fix your problem - using
public void move(int from, int to){
Track track = mArray.remove(from);
mArray.add(to, track);
notifyItemMoved(from, to);
ViewHolder fromHolder = (ViewHolder) mRecyclerView.findViewHolderForPosition(from);
ViewHolder toHolder = (ViewHolder) mRecyclerView.findViewHolderForPosition(to);
Tag fromTag = fromHolder.itemView.getTag();
fromHolder.itemView.setTag(toHolder.itemView.getTag());
toHolder.itemView.setTag(fromTag);
}
elgui
Updated on July 08, 2020Comments
-
elgui almost 4 years
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 ?
-
elgui over 9 yearsok, thank you for this answer =) but now what is the best way to retrieve the position from outside the adpater (my dragListener for example) ?
-
yigit over 9 yearsGet child view holder from recyclerview and then get position from the vh. See RecyclerView api for details
-
M. Erfan Mowlaei about 9 yearsYou saved me a lot of pain man, tyvm. BTW this should be accepted answer not the one above.
-
M. Erfan Mowlaei about 9 yearsand I forgot to say, if you are using DB to feed the adapter something like primary key for part 3 will solve your problem.
-
worked over 8 years1. notifyItemChanged(position)
-
Admin over 8 yearsHi, I don't understand what you need use "mItems.get(position).hashCode()" returns long I need return a object .., can you tell me ? and how return object ? thx
-
tochkov over 8 yearsIt is for your getItemId (int position) method which returns long.
-
jj. about 8 yearsgetPosition() was deprecated because it's too ambiguous. In this case you'll want to use getLayoutPosition()
-
kirtan403 about 8 yearsThat no 3 was something that turned my app Happy !! :) It can not control its emotions..
-
Daniel López Lacalle almost 8 yearsI love you. Like seriously :D
-
urSus over 7 yearsWhen removing, the view which was offscreen and should now slide in-screen just fades in, any way to make it slide instead?
-
user25 over 7 yearsbut
mAdapter.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
sucks. I see that items was movedCollections.swap(....,...)
but when I click on them they are old ones (so only titles of items were changed) -
alexbirkett about 7 yearsNot sure this is such a great idea because unequal objects can have the same hash codes eclipsesource.com/blogs/2012/09/04/…
-
HiddenDroid almost 7 yearsThank you @tochkov for the answer. It saved my life. Can you please give me some details about how this make it work? Or just refer me to a link or a video. Thx again
-
user3354265 about 6 years@tochkov Thanks a lot. you deserve a medal :)