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

如何在Kotlin中一次性选中RecyclerView内所有CheckBox?

问题:RecyclerView CheckBox 一键全选实现问题

我有一个包含CheckBox的RecyclerView,希望通过点击按钮一次性选中所有CheckBox。以下是我目前尝试的实现代码:

Adapter代码

class AdapterNfs (context: MainActivity, private val listener: OnItemClickListener) :
RecyclerView.Adapter<AdapterNfs.NfViewHolder>() {
    private val context: Context
    private var list = emptyList<ReceiverPayment>()
    private var status: Boolean = false

    init {
        this.context = context
    }

    fun setAllChecked(isChecked: Boolean){
        status = isChecked
        Log.d("***log", status.toString())
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NfViewHolder {
        val binding = ItemNotasFiscaisBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return NfViewHolder(binding)
    }

    override fun onBindViewHolder(holder: NfViewHolder, position: Int){
        holder.binding.apply {
            textNFnumber.text = list[position].id
            textNFvalue.text = list[position].totalValue
            nfStatus.text = list[position].paid.toString()
        }
        holder.binding.checkBoxNf.isChecked = status
    }

    override fun getItemCount() = list.size

    inner class NfViewHolder(var binding: ItemNotasFiscaisBinding) : RecyclerView.ViewHolder(binding.root), View.OnClickListener{

        init{
            binding.checkBoxNf.setOnClickListener(this)
        }

       override fun onClick(view: View?) {
            val checkbox = view as CheckBox
            val position : Int = adapterPosition
            val data = list
            if (position != RecyclerView.NO_POSITION) {
                 listener.onItemClick(position, checkbox.isChecked, data)
            }
       }
    }

    fun setData(newList: List<ReceiverPayment>) {
        val nfDiffUtil = DiffUtilGeneric(list, newList)
        val nfResult = DiffUtil.calculateDiff(nfDiffUtil)
        this.list = newList
        nfResult.dispatchUpdatesTo(this)
    }

    interface OnItemClickListener {
        fun onItemClick(
            position: Int,
            checked: Boolean,
            data: List<ReceiverPayment>
        )
    }
}

MainActivity代码

class MainActivity() : AppCompatActivity(), AdapterNfs.OnItemClickListener {
    private val myAdapter = AdapterNfs(this, this)
    private lateinit var binding : ActivityMainBinding
    private lateinit var mainViewModel: MainViewModel
    private lateinit var recyclerView: RecyclerView

    private var valueTotal = 00.00

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        mainViewModel = MainViewModel()

        setupRecyclerView()
        getAllNfs()
        setContentView(binding.root)

        binding.selectAllCheckBoxes.setOnClickListener {
            setAllCheckBoxes(true)
        }
    }

    override fun onItemClick(position: Int, checked: Boolean, data: List<ReceiverPayment>) {
        val totalValueSelected = binding.totalValue
        val nfSelected = data[position].totalValue.toString().toDouble()

        if (checked) {
            valueTotal += nfSelected
            totalValueSelected.text = valueTotal.toString()
        } else {
            valueTotal -= nfSelected
            totalValueSelected.text = valueTotal.toString()
        }
    }

    private fun setupRecyclerView(){
        recyclerView = binding.recyclerViewNfs
        binding.recyclerViewNfs.layoutManager = LinearLayoutManager(this)
        binding.recyclerViewNfs.itemAnimator = DefaultItemAnimator()
        binding.recyclerViewNfs.addItemDecoration(
            DividerItemDecoration(
                this,
                LinearLayoutManager.VERTICAL
            )
        )

        binding.recyclerViewNfs.adapter = myAdapter
    }

    private fun getAllNfs(){
        mainViewModel.allNfs.observe(this@MainActivity){response ->
            response.let {
                myAdapter.setData(it[0].receiverPayments as List<ReceiverPayment>)
            }
        }
    }

    private fun setAllCheckBoxes(isChecked: Boolean){
        myAdapter.setAllChecked(isChecked)
    }
}

问题分析与解决方案

1. 核心问题:未触发UI刷新

当前setAllChecked方法仅修改了status变量,但没有通知RecyclerView更新视图,导致CheckBox状态不会变化。需要在修改状态后调用刷新方法:

修改Adapter的setAllChecked方法:

fun setAllChecked(isChecked: Boolean){
    status = isChecked
    notifyItemRangeChanged(0, list.size) // 通知所有条目刷新UI
    Log.d("***log", status.toString())
}

2. 同步更新总金额

全选操作不会触发单个CheckBox的onClick事件,所以需要手动计算并更新总金额:

  • 先给Adapter添加公开的列表访问方法:
val currentList: List<ReceiverPayment> get() = list
  • 修改MainActivity的setAllCheckBoxes方法:
private fun setAllCheckBoxes(isChecked: Boolean){
    myAdapter.setAllChecked(isChecked)
    // 计算并更新总金额
    valueTotal = if (isChecked) {
        myAdapter.currentList.sumOf { it.totalValue.toString().toDouble() }
    } else {
        0.00
    }
    binding.totalValue.text = valueTotal.toString()
}

3. 优化方案:绑定数据与选中状态(更健壮)

仅靠全局status变量控制选中状态容易出现数据与UI不一致的问题,建议给ReceiverPayment添加isChecked字段:

  • 修改数据模型:
data class ReceiverPayment(
    // 原有字段...
    var isChecked: Boolean = false
)
  • 修改Adapter的onBindViewHolder:
holder.binding.checkBoxNf.isChecked = list[position].isChecked
  • 修改Adapter的setAllChecked:
fun setAllChecked(isChecked: Boolean){
    list.forEach { it.isChecked = isChecked }
    notifyItemRangeChanged(0, list.size)
}
  • 修改CheckBox点击逻辑,同步数据状态:
override fun onClick(view: View?) {
    val checkbox = view as CheckBox
    val position = adapterPosition
    if (position != RecyclerView.NO_POSITION) {
        list[position].isChecked = checkbox.isChecked
        listener.onItemClick(position, checkbox.isChecked, list)
    }
}

4. 可选:支持全选/反选切换

如果需要按钮切换全选和取消全选,可在MainActivity中维护状态:

private var isAllSelected = false

// 修改按钮点击事件
binding.selectAllCheckBoxes.setOnClickListener {
    isAllSelected = !isAllSelected
    setAllCheckBoxes(isAllSelected)
    binding.selectAllCheckBoxes.text = if (isAllSelected) "取消全选" else "全选"
}

内容的提问来源于stack exchange,提问作者Gabriel Romão

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 23:31:05