由于 ItemTouchHelper 和 DiffUtil 之间的冲突导致不需要的动画
Unwanted animation due to conflict between ItemTouchHelper and DiffUtil
我正在实现一个支持拖放的 RecyclerView。当一个项目被删除时,该项目的索引列将在 Room 数据库中更新以存储更新的排序。
我面临的问题是,当我在删除项目后调用 Room 数据库更新时,因为项目列表是 ViewModel 中的 LiveData 并通过 Databinding 绑定到 RecyclerView,DiffUtil 将重新计算项目位置和内容紧随其后,1. 添加了新的不需要的动画和 2. 有时内容没有正确刷新。
ItemTouchHelper:
val helper = ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP or ItemTouchHelper.DOWN or
ItemTouchHelper.START or ItemTouchHelper.END, 0
) {
var dragFrom = -1
var dragTo = -1
override fun onMove(
recyclerView: RecyclerView, selected: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
val from = selected.adapterPosition
val to = target.adapterPosition
if (dragFrom == -1) {
dragFrom = from
}
dragTo = to
recyclerView.adapter?.notifyItemMoved(from, to)
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
}
override fun clearView(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
) {
if (dragFrom != -1 && dragTo != -1 && dragFrom != dragTo) {
val fromId = myAdapter.getItemId(dragFrom)
detailViewModel.updateItemIndex(fromId, calcNewIndex(dragFrom, dragTo))
}
super.clearView(recyclerView, viewHolder)
dragFrom = -1
dragTo = -1
}
})
helper.attachToRecyclerView(binding.detailRecyclerview)
MyAdapter 中的 DiffUtil:
class NoteDiffCallback : DiffUtil.ItemCallback<MyNote>() {
override fun areItemsTheSame(oldItem: MyNote, newItem: MyNote): Boolean {
return oldItem.noteId == newItem.noteId
//return true (replacing this will mostly fix the ItemTouchHelper issues, but also removes other animations that I want, such as inserting)
}
override fun areContentsTheSame(oldItem: MyNote, newItem: MyNote): Boolean {
return oldItem == newItem
}
}
我想更改它以使 DiffUtil 不干扰 ItemTouchHelper,但我仍想保留 DiffUtil 以在插入新笔记时获得漂亮的动画效果。将不胜感激。
诀窍是更新 ItemTouchHelper.Callback
中的 ListAdapter
项,这样来自 Room 数据库的更新不会执行任何操作,因为这些项已经相等。
class ItemTouchHelperCallback(val adapter: MyNoteAdapter) :
ItemTouchHelper.Callback() { // you need a reference to your adapter
...
override fun onMove(
recyclerView: RecyclerView, selected: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
val from = selected.adapterPosition
val to = target.adapterPosition
if (dragFrom == -1) {
dragFrom = from
}
dragTo = to
val items = adapter.currentList.toMutableList()
Collections.swap(items, from, to)
adapter.submitList(items) // calls adapter.notifyItemMoved(), so we don't have to
return true
}
...
}
我正在实现一个支持拖放的 RecyclerView。当一个项目被删除时,该项目的索引列将在 Room 数据库中更新以存储更新的排序。
我面临的问题是,当我在删除项目后调用 Room 数据库更新时,因为项目列表是 ViewModel 中的 LiveData 并通过 Databinding 绑定到 RecyclerView,DiffUtil 将重新计算项目位置和内容紧随其后,1. 添加了新的不需要的动画和 2. 有时内容没有正确刷新。
ItemTouchHelper:
val helper = ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP or ItemTouchHelper.DOWN or
ItemTouchHelper.START or ItemTouchHelper.END, 0
) {
var dragFrom = -1
var dragTo = -1
override fun onMove(
recyclerView: RecyclerView, selected: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
val from = selected.adapterPosition
val to = target.adapterPosition
if (dragFrom == -1) {
dragFrom = from
}
dragTo = to
recyclerView.adapter?.notifyItemMoved(from, to)
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
}
override fun clearView(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
) {
if (dragFrom != -1 && dragTo != -1 && dragFrom != dragTo) {
val fromId = myAdapter.getItemId(dragFrom)
detailViewModel.updateItemIndex(fromId, calcNewIndex(dragFrom, dragTo))
}
super.clearView(recyclerView, viewHolder)
dragFrom = -1
dragTo = -1
}
})
helper.attachToRecyclerView(binding.detailRecyclerview)
MyAdapter 中的 DiffUtil:
class NoteDiffCallback : DiffUtil.ItemCallback<MyNote>() {
override fun areItemsTheSame(oldItem: MyNote, newItem: MyNote): Boolean {
return oldItem.noteId == newItem.noteId
//return true (replacing this will mostly fix the ItemTouchHelper issues, but also removes other animations that I want, such as inserting)
}
override fun areContentsTheSame(oldItem: MyNote, newItem: MyNote): Boolean {
return oldItem == newItem
}
}
我想更改它以使 DiffUtil 不干扰 ItemTouchHelper,但我仍想保留 DiffUtil 以在插入新笔记时获得漂亮的动画效果。将不胜感激。
诀窍是更新 ItemTouchHelper.Callback
中的 ListAdapter
项,这样来自 Room 数据库的更新不会执行任何操作,因为这些项已经相等。
class ItemTouchHelperCallback(val adapter: MyNoteAdapter) :
ItemTouchHelper.Callback() { // you need a reference to your adapter
...
override fun onMove(
recyclerView: RecyclerView, selected: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
val from = selected.adapterPosition
val to = target.adapterPosition
if (dragFrom == -1) {
dragFrom = from
}
dragTo = to
val items = adapter.currentList.toMutableList()
Collections.swap(items, from, to)
adapter.submitList(items) // calls adapter.notifyItemMoved(), so we don't have to
return true
}
...
}