Как правильно написать DiffUtil.Callback, чтобы в окне реселлера анимация перемещалась? - PullRequest
0 голосов
/ 02 апреля 2020

У меня есть адаптер recyclerview со старым типом данных, в моем случае char.

Адаптер поддерживается списком.

Метод setChar обновляет список.

Предположим, что в моем случае setChar вызывается только с тем же списком, что и адаптер, но только с перемещенными элементами.

fun setChar(list: List<Char>) {
    val diffResult = DiffUtil.calculateDiff(CharDiffCallBack(mChars, list), true)
    mChars = list
    diffResult.dispatchUpdatesTo(this)
}

class CharDiffCallBack(private val mOldList: List<Char>, private val mNewList: List<Char>) :
    DiffUtil.Callback() {
    override fun getOldListSize() = mOldList.size
    override fun getNewListSize() = mNewList.size
    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) = mOldList[oldItemPosition] == mNewList[newItemPosition]
    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) = false
}

Какая корректная реализация DiffUtil.Callback, так что ходы корректно анимируются как ходы в окне повторного просмотра?

В настоящее время анимируется, как если бы элемент был удален и вставлен заново.

1 Ответ

0 голосов
/ 02 апреля 2020

Мне кажется, что вы допустили две ошибки одновременно.

Первая (не уверен, что это ошибка, но обычно она совершается противоположным образом): вы вернуть false из метода areContentsTheSame. Это заставляет RecyclerView повторно привязать видоискатель. Это не так, если изменился только порядок элемента, возвращайте false, только если вам нужно повторно привязать видоискатель. Поэтому, если содержимое элементов не изменяется, по умолчанию возвращается true.

Второй подозреваемый - ваш setChar метод. Кажется, что DiffCallback принимает два одинаковых списка все время. Если у вас есть список данных в активности / фрагменте и вы передаете тот же List для установки новых данных, то это заставляет DiffCallback работать некорректно, поскольку DiffCallback не видит никаких изменений позиции в ваших списках как они оба равны.

Я только что проверил, и только комбинация этих двух дает результат, который у вас есть. Итак, что вы должны сделать:

class YourAdapter(..., charList: List<Char>, ...): RecyclerView.Adapter<...>() {
    private val mChars = ArrayList(charList)
    // You have to keep a different List object (so, a copy) of the one you pass from the activity
    ...

    fun setChar(list: List<Char>) {
        val diffResult = DiffUtil.calculateDiff(CharDiffCallBack(mChars, list), true)
        mChars.clear()
        mChars.addAll(list)
        diffResult.dispatchUpdatesTo(this)
    }
}

class CharDiffCallBack(private val mOldList: List<Char>, private val mNewList: List<Char>) :
    DiffUtil.Callback() {
    ...
    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) = true
}

Таким образом DiffCallback всегда берет два разных списка, один старый и один с обновленными данными. Также верните true из areContentsTheSame method

...