Reputation: 1505
Well, I have a RecyclerView with an adapter and everything works great. The items in the ArrayList dataset are being updated periodically. So the items and their elements as well as their position in the list change. This is achieved by simple sorting and manually calling these methods, whenever things happen:
// swapping two items
Collections.swap(items, i, j);
itemsAdapter.notifyItemMoved(i, j);
// adding a new one
itemAdapter.notifyItemInserted(items.size());
// when updating valus
itemAdapter.notifyItemChanged(i);
The latter of which, is the cause of my misery. Every time an item is updated, a little "blink" animation is triggered.
I found a couple of solutions for this:
// disabling all animations
recyclerView.getItemAnimator().setSupportsChangeAnimations(false);
// or
// setting the animation duration to zero,
recyclerView.getItemAnimator().setChangeDuration(0);
But both of these kill the animations when items move (being swapped). I just want to override the one animation and keep all of this magic. Is there a way of doing this? And if it's overriding ItemAnimator, does anyone have a simple example?
Thanks in advance!
Upvotes: 76
Views: 51024
Reputation: 2517
There is a dedicated method to disable just item changed animations:
((SimpleItemAnimator) myRecyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
Upvotes: 126
Reputation: 16619
Kotlin version of @Pablo A. Martínez answer:
(recyclerView.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
Upvotes: 15
Reputation: 4371
If you are only modifying the data of Recyclerview means no addition or deletion of item then you should add this line.
mRecyclerview.setHasFixedSize(true);
So that recyclerview will get to know there is no change in size after that you can apply
((SimpleItemAnimator) mRecyclerview.getItemAnimator()).setSupportsChangeAnimations(false);
So that animation will be disappear and code will work like charm :)
Upvotes: 5
Reputation: 11
In my case the recyclerview took all the space below toolbar. All I did was changing the layout_height of recyclerview from wrap_content to match_parent and blinking disappeared.
Upvotes: 1
Reputation: 41
Slight variation on Alex's answer.
Instead of removing the alpha change altogether, I just reduced it. the only changes needed were:
//changed alpha from 0
ViewCompat.setAlpha(newHolder.itemView, 0.5f);
and
//changed alpha from 0
oldViewAnim.alpha(0.5f).setListener(new VpaListenerAdapter() {
In both cases, change the 0 to 0.5 This has the effect of removing the flicker associated with the alpha going completely to 0, but keeps the morphing qualities of the item change animation.
Upvotes: 4
Reputation: 1505
Yes, I did.
First, get the source code of DefaultItemAnimator. Take the code and create a class named MyItemAnimator in your project. Then, set the ItemAnimator to a new instance of your modified MyItemAnimator, like so:
recyclerView.setItemAnimator(new MyItemAnimator());
Now, go in the new classes source code and locate the method
animateChangeImpl(final ChangeInfo changeInfo) { ... }
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() { ... }
Upvotes: 23