Kotlin如何实现RecyclerView取消选中及状态校验
RecyclerView单选逻辑异常修复方案
问题根因
- 取消选中条目时未将全局选中位置标记
checkPosition重置为-1,导致状态判定始终认为存在选中项,操作按钮无法同步禁用;同时点击回调仅传递了条目数据,未告知外层当前是选中还是取消操作,外层逻辑无法同步更新按钮状态。 - 选中列表维护逻辑缺失:现有代码仅在选中时触发回调,未处理取消选中时从存储列表移除数据的逻辑;
updateChecked方法逻辑错误,仅做了全量匹配标记选中,未适配取消选中的场景,且代码存在多处变量名混用(数据源listPul/listpul/listp、控件IDitemPul/itemP),极易引发非预期逻辑错误。
修复点说明
- 补全点击事件的状态切换逻辑:点击已选中条目执行取消操作时,将
checkPosition重置为-1,回调时同步传递当前选中状态,外层拿到状态后可直接控制按钮启用/禁用。 - 补全选中列表维护逻辑:选中条目时将对应数据加入存储选中项的ArrayList,取消选中时移除对应数据。
- 统一所有变量命名,修复控件、数据源变量名不一致的笔误,移除点击事件中手动修改UI的逻辑,所有UI状态统一靠
notify触发onBind重绘,避免状态错乱。
修复后核心代码
// 选中项存储列表,和你外层使用的ArrayList保持同一份引用即可 private val selectedItems = arrayListOf<Model>() private var checkPosition = -1 private lateinit var listPul: List<Model> // 统一数据源变量名 private lateinit var listener: OnItemClickListener // 统一数据源提交方法,替换原有命名混乱的数据源赋值逻辑 fun submitList(list: List<Model>) { this.listPul = list notifyDataSetChanged() } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GridViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_pul, parent, false) return GridViewHolder(view) } override fun onBindViewHolder(holder: GridViewHolder, position: Int) { holder.bindPul(listPul[position]) } override fun getItemCount(): Int = listPul.size inner class GridViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){ fun bindPul(pul: Model) = with(itemView){ val binding = ItemPulBinding.bind(itemView) // 统一控件绑定类名,和布局名保持一致 binding.lblPayAmount.text = pul.ModelValue.toDouble().currencyFormatter() // 所有UI状态统一在bind方法里渲染,避免手动改UI导致的状态错位 if (checkPosition == absoluteAdapterPosition) { binding.itemPul.setCardBackgroundColor(Color.parseColor("#F5FAFF")) binding.itemPul.strokeColor = Color.TRANSPARENT binding.lblCheck.setVisible(true) } else { binding.itemPul.setCardBackgroundColor(Color.WHITE) binding.itemPul.strokeColor = Color.parseColor("#DDEBF9") binding.lblCheck.setVisible(false) } setOnClickListener { val isSelected: Boolean if (checkPosition != absoluteAdapterPosition) { // 选中新条目:先刷新旧选中项恢复未选中状态,更新选中位置标记 notifyItemChanged(checkPosition) checkPosition = absoluteAdapterPosition pul.isSelected = true // 单选场景维护选中列表:先清空旧数据,再加入新选中项 selectedItems.clear() selectedItems.add(pul) isSelected = true } else { // 取消当前选中:重置选中位置为-1 checkPosition = -1 pul.isSelected = false // 从选中列表移除当前取消的条目 selectedItems.remove(pul) isSelected = false } // 刷新当前项UI状态 notifyItemChanged(absoluteAdapterPosition) // 回调时同步传递选中状态,外层可直接根据该值控制按钮启用/禁用 listener.onItemClick(pul, isSelected) } } } // 修正后的选中状态更新方法 fun updateChecked(item: Model){ listPul.forEach { model -> model.isSelected = model.ModelValue == item.ModelValue } checkPosition = listPul.indexOfFirst { it.ModelValue == item.ModelValue } notifyDataSetChanged() } // 修改回调接口,增加选中状态参数 interface OnItemClickListener { fun onItemClick(pul: Model, isSelected: Boolean) }
外层调用注意点
实现OnItemClickListener时,直接根据回调返回的isSelected参数控制操作按钮状态即可:参数为true时启用按钮,为false时禁用按钮,不需要额外做其他值校验。
内容的提问来源于stack exchange,提问作者foreverstudents
相关产品推荐
相关产品推荐

