【发布时间】:2021-04-24 12:50:28
【问题描述】:
目前,我有一个 RecyclerView 实现了新的 ListAdapter,使用 submitList 来区分不同的元素并继续自动更新 UI。
最近我不得不使用众所周知的 ItemTouchHelper 实现拖放到列表。这是我的实现,非常简单:
class DraggableItemTouchHelper(private val adapter: DestinationsAdapter) : ItemTouchHelper.Callback() {
private val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN
private val swipeFlags = 0
override fun isLongPressDragEnabled() = false
override fun isItemViewSwipeEnabled() = false
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
return makeMovementFlags(dragFlags, swipeFlags)
}
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
val oldPos = viewHolder.adapterPosition
val newPos = target.adapterPosition
adapter.swap(oldPos, newPos)
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
}
}
这是我在适配器内部的交换函数:
fun swap(from: Int, to: Int) {
submitList(ArrayList(currentList).also {
it[from] = currentList[to]
it[to] = currentList[from]
})
}
除了移动列表的第一项时,一切正常。有时它的行为还可以,但大多数时候(如 90%),即使将其移动到第二个项目的上方(例如将第一个项目移动到第二个位置),它也会捕捉多个位置。新职位似乎是随机的,我无法弄清楚问题所在。
作为指导,我使用https://github.com/material-components/material-components-android 示例来实现拖放,并且它们的(简单)列表和布局效果很好。我的列表有点复杂,因为它在 viewpager 中,使用 Navigation 组件,并且在该屏幕中约束在一起的许多其他视图,但我认为这不应该相关。
此时我什至不知道如何在网上搜索此问题。 我为此找到的最接近的解决方案可能是https://issuetracker.google.com/issues/37018279,但在实现并具有相同的行为之后,我认为这是因为我使用不同的 ListAdapter 并异步更新列表,当解决方案使用 RecyclerView.Adapter 它使用 notifyItemMoved 和其他类似方法。
切换到 RecyclerView.Adapter 不是解决方案。
【问题讨论】:
-
这里有同样的问题。对我来说,当没有项目超出可见屏幕空间时拖动第一个项目,它工作正常。但是,当屏幕上有项目时拖动它(recyclerView 是可滚动的)然后它会跳转多个位置。这是一个模式,如果屏幕外有 1 个项目,第一个项目会跳 2 个位置。如果屏幕外有 2 个项目,则它会跳转 3 个位置,依此类推。它具有这种 (n, n+1) 行为,其中 n = 屏幕外的项目数。我已经在 3 个模拟器和一个物理设备上验证了这种模式。这是你的经历吗?
-
所以经过更多研究,我发现第一个项目没有捕捉,而是整个屏幕都在滚动(在我的情况下,一直向下显示屏幕外的最后一个项目,无论出于何种原因) .尽管here 的答案对我没有帮助,但他们帮助了其他人,希望对您有所帮助。
-
@gig6 我遇到了同样的问题。我的问题的所有细节都和你的一样。我一直在尝试找到一种方法将列表提交给
ListAdapter,而不是让它通知RecyclerView的更改,所以我可以自己通过调用notifyItemMoved()来完成(这样它工作得很好)。但是,我没有找到实现这一目标的方法。也许我应该为此提交功能请求,或者报告 Diff Util 在所描述的情况下表现异常的错误。 -
@gig6 我实际上设法找到了解决方案:在下面查看我的答案。
标签: android android-recyclerview scroll drag-and-drop