You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin如何实现RecyclerView取消选中及状态校验

RecyclerView单选逻辑异常修复方案

问题根因

  • 取消选中条目时未将全局选中位置标记checkPosition重置为-1,导致状态判定始终认为存在选中项,操作按钮无法同步禁用;同时点击回调仅传递了条目数据,未告知外层当前是选中还是取消操作,外层逻辑无法同步更新按钮状态。
  • 选中列表维护逻辑缺失:现有代码仅在选中时触发回调,未处理取消选中时从存储列表移除数据的逻辑;updateChecked方法逻辑错误,仅做了全量匹配标记选中,未适配取消选中的场景,且代码存在多处变量名混用(数据源listPul/listpul/listp、控件IDitemPul/itemP),极易引发非预期逻辑错误。

修复点说明

  1. 补全点击事件的状态切换逻辑:点击已选中条目执行取消操作时,将checkPosition重置为-1,回调时同步传递当前选中状态,外层拿到状态后可直接控制按钮启用/禁用。
  2. 补全选中列表维护逻辑:选中条目时将对应数据加入存储选中项的ArrayList,取消选中时移除对应数据。
  3. 统一所有变量命名,修复控件、数据源变量名不一致的笔误,移除点击事件中手动修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 07:42:15