RecyclerView调用notifyDataSetChanged后长按item勾选Checkbox错位问题
问题根因
- 未存储条目选中状态:你仅在交互时修改了当前Holder中Checkbox的选中属性,没有用独立的数据结构记录每个位置的选中状态。当调用
notifyDataSetChanged()触发全量刷新、或者滑动列表触发ViewHolder复用时,系统会直接复用Holder上一次渲染的UI状态,导致选中错位。当元素少于等于5个时,列表一屏可以完全展示,不需要复用ViewHolder,所以运行正常;超过5个后触发复用逻辑,就会出现误勾选的问题。 - 代码存在冗余隐患:你在Adapter全局声明了
binding变量,每次onCreateViewHolder创建新Holder时都会覆盖这个全局变量,虽然当前逻辑使用Holder内部存储的binding操作不会直接引发bug,但这个写法不规范,后续修改逻辑很容易出错。
修复方案
首先新增一个集合存储已选中的位置,同时在onBindViewHolder中主动给Checkbox赋值选中状态,交互时先修改数据源再刷新UI,删除全局冗余的binding变量,修改后代码如下:
class RecyclerAdapter(private val listActivity: ListActivity) : RecyclerView.Adapter<RecyclerAdapter.Holder>() { var checkboxesVisibility = false val dummyArrayFails = arrayOf("000", "111", "222", "333", "444", "555") // 新增存储选中位置的集合 private val checkedPositions = mutableSetOf<Int>() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder { // 局部声明binding,不要用全局变量 val binding = ActivityListItemRowBinding.inflate(LayoutInflater.from(parent.context), parent, false) return Holder(binding) } override fun getItemCount(): Int = dummyArrayFails.size override fun onBindViewHolder(holder: Holder, position: Int) { val item = dummyArrayFails[position] holder.bindItem(item) // 主动设置可见性和选中状态,避免复用错乱 holder.binding.checkbox.visibility = if (checkboxesVisibility) View.VISIBLE else View.GONE holder.binding.checkbox.isChecked = checkedPositions.contains(position) holder.itemView.setOnLongClickListener { if (!checkboxesVisibility) { checkboxesVisibility = true // 先修改数据,不要直接改Holder的控件状态 checkedPositions.add(position) notifyDataSetChanged() true } else { false } } holder.itemView.setOnClickListener { if (!checkboxesVisibility) { // 其他业务逻辑 } else { // 先修改数据 if (checkedPositions.contains(position)) { checkedPositions.remove(position) } else { checkedPositions.add(position) } notifyDataSetChanged() } } } class Holder(internal val binding: ActivityListItemRowBinding) : RecyclerView.ViewHolder(binding.root) { var item = String() fun bindItem(item: String) { this.item = item binding.itemPlaceHolder.text = item } } }
另外你提到去掉显隐逻辑直接显示Checkbox就不会错位,是因为这种场景下你没有触发notifyDataSetChanged全量刷新,且没有滑动列表触发复用,一旦滑动或者刷新同样会出现错位问题。
内容的提问来源于stack exchange,提问作者Linus Karlsson
相关产品推荐
相关产品推荐

