Подтвердить что ты не робот

Переопределить анимацию для 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, есть ли у кого-нибудь простой пример?

Спасибо заранее!

4b9b3361

Ответ 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