I am using a RecyclerView
with ListAdapter
in which I display 2 types of items: content & placeholder.
In this example the initial list consists of 10 content items and 10 placeholder items, which I then replace with another 10 content items (= always 20 items in total).
Doing this with ListAdapter.submitList(list)
works as expected and shows the correct change animations. Like in this GIF:
However, when I'm scrolling to a part of the screen where only placeholders are shown then .submitList(list)
causes an unwanted scroll, like seen in this GIF:
My diffing logic: (Should be fine, generally all animations work as expected)
sealed class MyItem {
data class Content(val text: String) : MyItem()
data class Placeholder(val text: String) : MyItem()
}
class MyDiffCallback : DiffUtil.ItemCallback<MyItem>() {
override fun areItemsTheSame(oldItem: MyItem, newItem: MyItem): Boolean =
oldItem::class == newItem::class && when (oldItem) {
is MyItem.Content -> oldItem.text == (newItem as MyItem.Content).text
is MyItem.Placeholder -> oldItem.text == (newItem as MyItem.Placeholder).text
}
override fun areContentsTheSame(oldItem: MyItem, newItem: MyItem): Boolean =
oldItem == newItem
}
What could be wrong? Is this actually working as expected and I'm just missing something?
- I checked some solutions from other Stackoverflow questions already - mostly about making the RecyclerView and the items not focusable e.g. here - they didn't fix my problem.
- I also tried to use a normal
RecyclerView.Adapter
and do the diffing of the new list manually viaDiffUtil.calculateDiff(...)
- this has the same issue (ListAdapter
usesDiffUtil
internally after all) - I managed to do a workaround by doing
adapter.notifyItemRangeChanged(...)
on the exact items which changed - this worked and doesn't cause a scroll, but I'm not happy with this workaround and don't want to apply it in all my features
try this in areContentsTheSame()