【发布时间】:2021-09-27 17:19:52
【问题描述】:
我有一个从房间数据库更新的列表。我从 Room 接收更新的数据作为新列表,然后将其传递给 ListAdapter 的 submitList 以获取更改的动画。
list.observe(viewLifecycleOwner, { updatedList ->
listAdapter.submitList(updatedList)
})
现在,我想为同一个 RecyclerView 添加拖放功能。我尝试使用ItemTouchHelper 来实现它。但是,notifyItemMoved() 不起作用,因为 ListAdapter 通过 submitList() 更新其内容。
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
val from = viewHolder.bindingAdapterPosition
val to = target.bindingAdapterPosition
val list = itemListAdapter.currentList.toMutableList()
Collections.swap(list, from, to)
// does not work for ListAdapter
// itemListAdapter.notifyItemMoved(from, to)
itemListAdapter.submitList(list)
return false
}
现在拖放工作正常,但只有在缓慢拖动时,当拖动速度足够快时,我会得到不同且不一致的结果。
这可能是什么原因?为使用 ListAdapter 的 RecyclerView 实现拖放功能的最佳方式是什么?
【问题讨论】:
-
已经有一段时间了,但位置不应该是
adapterPosition而不是bindingAdapterPosition还是因为 ViewBinding 而出现的新事物? -
adapterPosition现在已弃用并替换为absoluteAdapterPosition或bindingAdapterPosition -
啊,谢谢。我应该更频繁地阅读文档。我认为问题在于将集合复制(到可变列表),然后移动项目,最后提交列表需要使用 Diff Util 来计算更改所需的“时间”。其中大部分是异步的,因此可能是时间问题。您在列表中使用 DiffUtil 或 AsyncDiffUtil 吗?你能展示你的diff Util吗?你有多少物品?您在 onItemMoved 中看到了多少次调用(当您拖动时)?
-
是的,这可能是时间问题。
ListAdapter使用AsyncListDiffer。我的 diff util 比较 id 的 onareItemsTheSame,然后比较areContentsTheSame的内容。我什至尝试在没有包含许多内容的自定义对象的情况下做到这一点,而只使用字符串但仍然遇到同样的问题。onItemMoved被称为与缓慢拖动时位置变化的数量相同的数量,并且在快速拖动时不一致的计数(小于假设的数量,因为有些被跳过)。 -
(不相关)但您可以使用 Kotlin 的价值捕获魔法保存 Collections.Swap 调用:
list[from] = list[to].also { list[to] = list[from] }(尽管我认为这对于新手和基本上任何阅读此代码的人来说都比较模糊) :)
标签: android android-recyclerview listadapter