Переопределить анимацию для notifyItemChanged в RecyclerView.Adapter
Ну, у меня есть RecyclerView с адаптером, и все работает отлично. Периодически обновляются обновления в наборе данных ArrayList. Таким образом, элементы и их элементы, а также их позиция в списке меняются. Это достигается простой сортировкой и ручным вызовом этих методов, когда что-то происходит:
// 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);
Последний из которых является причиной моего страдания. Каждый раз, когда элемент обновляется, запускается небольшая анимация "мигания".
Я нашел пару решений для этого:
// disabling all animations
recyclerView.getItemAnimator().setSupportsChangeAnimations(false);
// or
// setting the animation duration to zero,
recyclerView.getItemAnimator().setChangeDuration(0);
Но оба они убивают анимацию, когда элементы перемещаются (меняются местами). Я просто хочу переопределить одну анимацию и сохранить всю эту магию. Есть ли способ сделать это? И если он переопределяет ItemAnimator, есть ли у кого-нибудь простой пример?
Спасибо заранее!
Ответы
Ответ 1
Да, я сделал.
Сначала получите исходный код DefaultItemAnimator. Возьмите код и создайте в своем проекте класс MyItemAnimator. Затем установите ItemAnimator в новый экземпляр модифицированного MyItemAnimator, например:
recyclerView.setItemAnimator(new MyItemAnimator());
Теперь перейдите в исходный код новых классов и найдите способ
animateChangeImpl(final ChangeInfo changeInfo) { ... }
Нам просто нужно найти вызов метода, изменяющий альфа-значения. Найдите следующие две строки и удалите .alpha(0) и α (1)
oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() { ... }
newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()).alpha(1).setListener(new VpaListenerAdapter() { ... }
так
oldViewAnim.setListener(new VpaListenerAdapter() { ... }
newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()).setListener(new VpaListenerAdapter() { ... }
Ответ 2
Существует выделенный метод, позволяющий отключить только измененные анимации элемента:
((SimpleItemAnimator) myRecyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
Официальные документы.
Ответ 3
Незначительное изменение ответа Алекса.
Вместо того, чтобы полностью удалить альфа-изменение, я просто уменьшил его. необходимы только следующие изменения:
//changed alpha from 0
ViewCompat.setAlpha(newHolder.itemView, 0.5f);
и
//changed alpha from 0
oldViewAnim.alpha(0.5f).setListener(new VpaListenerAdapter() {
В обоих случаях измените значение 0 на 0,5
Это приводит к удалению фликкера, связанного с альфа-движением, полностью равным 0, но сохраняет морфинговые качества анимации изменения элемента.
Ответ 4
Попробуйте установить:
mRecyclerview.setItemAnimator(null);
Ответ 5
В моем случае recyclerview занял все пространство под панелью инструментов. Все, что я сделал, это изменение layout_height recyclerview от wrap_content до match_parent и мигание исчезло.
Ответ 6
Если вы только изменяете данные Recyclerview, это означает, что вы не добавили или не удалили элемент, а затем добавьте эту строку.
mRecyclerview.setHasFixedSize(true);
Так что recyclerview узнает, что после изменения вы не сможете изменить размер
((SimpleItemAnimator) mRecyclerview.getItemAnimator()).setSupportsChangeAnimations(false);
Итак, анимация исчезнет, и код будет работать как шарм:)
Ответ 7
Kotlin версия @Pablo A. Martínez ответ:
(mRecyclerview.getItemAnimator() as SimpleItemAnimator).supportsChangeAnimations = false