使用ItemTouchHelper删除Adapter条目后无法滑动的问题
我帮你排查了代码里的几个核心问题,这就是删除第一个条目后无法继续滑动的根源:
1. 只读集合的修改异常
你的data变量定义成了List<User>,这是Kotlin的只读集合,本身没有removeAt()方法。调用data.removeAt(position)会直接抛出UnsupportedOperationException,导致后续的notifyItemRemoved()和notifyItemRangeChanged()都无法执行。这会让RecyclerView的UI状态和数据源完全脱节,后续的滑动逻辑自然就失效了。
修复方法:
把data改为可变集合MutableList:
class Adapter: RecyclerView.Adapter<BaseUserVH>() { private var data: MutableList<User> = mutableListOf() // 替换为MutableList private var activeUserPosition = 0 // ... 其他代码保持不变 }
2. Active位置未同步更新
当你删除的条目位置小于等于activeUserPosition时,activeUserPosition没有同步调整,会导致后续条目的ViewType判断错误(比如原来的第二个条目现在变成position 0,但activeUserPosition还是0,会被错误标记为Active类型)。虽然这不是直接导致滑动失效的原因,但会引发其他UI异常,建议一起修复。
修复方法:
在updateItemRemoved()里同步更新activeUserPosition:
fun updateItemRemoved(position: Int) { data.removeAt(position) // 如果删除的是active条目或active位置在删除位置之后,调整索引 if (activeUserPosition >= position) { activeUserPosition = max(0, activeUserPosition - 1) } notifyItemRemoved(position) notifyItemRangeChanged(position, itemCount) }
3. 使用更可靠的Position获取方式
在ItemTouchHelper的onSwiped()中,你用了viewHolder.layoutPosition,但更可靠的是viewHolder.adapterPosition——它代表条目在Adapter中的最新位置,能避免因布局未及时更新导致的位置错误。
修复方法:
修改swipeToDelete里的回调逻辑:
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { val position = viewHolder.adapterPosition if (position != RecyclerView.NO_POSITION) { // 额外判断,避免无效位置 onSwiped(position) } }
4. 滑动限制逻辑的潜在优化
你的getMovementFlags里判断了只剩最后一个条目时禁止滑动,这个逻辑没问题,但如果activeUserPosition对应的条目你不希望被滑动,可以补充判断:
override fun getMovementFlags( recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder ): Int { val position = viewHolder.adapterPosition if (position == RecyclerView.NO_POSITION) return 0 // 如果是active条目,禁止滑动(根据你的业务需求调整) if (position == activeUserPosition) return 0 // 原有的最后一个条目禁止滑动逻辑 return if (adapter?.itemCount ?: 0 == 1 && position == 0) 0 else super.getMovementFlags(recyclerView, viewHolder) }
把这些修改都应用后,滑动删除的逻辑就能正常工作了。
内容的提问来源于stack exchange,提问作者P.Juni

