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

Kotlin中RecyclerView内Radio Button选中状态异常问题

问题解决:RecyclerView中RadioButton无法互斥选中

问题根源

  1. 每个列表项的RadioButton都被包裹在独立的RadioGroup中,系统无法跨Item管理单选互斥逻辑。
  2. 点击RadioButton时未更新数据源的选中状态,也未通知Adapter刷新UI。
  3. 没有维护全局选中标记,无法自动取消其他Item的选中状态。

解决方案步骤

1. 修改列表项XML,移除多余的RadioGroup

单个RadioButton不需要RadioGroup包裹,直接保留RadioButton即可:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="filterItemName"
            type="com.xxx.xxxxx.datamodel.FilterByItemDataModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="5dp"
        android:layout_marginEnd="5dp">

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/filter_item_txt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:layout_marginBottom="5dp"
            android:padding="10dp"
            android:textColor="@color/txt_black"
            android:textSize="14sp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:layout_marginTop="5dp"
            android:background="@color/txt_light_grey"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/filter_item_txt" />

        <!-- 移除RadioGroup,直接保留RadioButton -->
        <androidx.appcompat.widget.AppCompatRadioButton
            android:id="@+id/filter_radio_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:visibility="gone"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

2. 修改Adapter,维护选中状态并处理互斥逻辑

在Adapter中添加全局选中位置变量,点击时更新所有数据的选中状态并刷新Adapter:

class FilterByDataAdapter(
    val filterByData: (ArrayList<String>) -> Unit, 
    val filterByDataRadioBtn: (String) -> Unit
) : RecyclerView.Adapter<FilterByDataAdapter.FilterByDataViewHolder>() {

    private lateinit var filerByDataList: ArrayList<FilterByItemDataModel>
    private lateinit var filterByName: String
    // 维护当前选中的位置,初始为-1表示未选中
    private var selectedPosition = -1

    var filteredData: ArrayList<String> = arrayListOf()

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

    override fun onBindViewHolder(holder: FilterByDataViewHolder, position: Int) {
        val filterByDataItem = filerByDataList[position]
        holder.bindFilterByData(filterByDataItem, filterByName, position)
    }

    override fun getItemCount(): Int = filerByDataList.size

    fun setFilterByDataList(
        filterByTimeList: ArrayList<FilterByItemDataModel>, 
        filterName: String
    ) {
        filerByDataList = filterByTimeList
        filterByName = filterName
        notifyDataSetChanged()
    }

    inner class FilterByDataViewHolder(private val binding: ItemFilterByListBinding) :
        RecyclerView.ViewHolder(binding.root) {
        fun bindFilterByData(
            filterByItemDataModel: FilterByItemDataModel, 
            filterByName: String,
            position: Int
        ) {
            binding.filterItemTxt.text = filterByItemDataModel.itemName

            when (filterByName) {
                TIME -> {
                    binding.filterRadioBtn.visibility = View.VISIBLE
                    // 根据选中位置设置RadioButton状态
                    binding.filterRadioBtn.isChecked = selectedPosition == position

                    // 用OnClickListener代替OnCheckedChangeListener,避免复用问题
                    binding.filterRadioBtn.setOnClickListener {
                        // 更新选中位置
                        selectedPosition = position
                        // 更新所有数据的isChecked状态
                        filerByDataList.forEachIndexed { index, item ->
                            item.isChecked = index == selectedPosition
                        }
                        // 通知Adapter刷新
                        notifyDataSetChanged()
                        // 回调选中的项
                        filterByDataRadioBtn.invoke(filterByItemDataModel.itemName.toString())
                    }
                }

                STATUS, VALIDITY -> {
                    binding.filterCheckBoxBtn.visibility = View.VISIBLE
                    binding.filterCheckBoxBtn.isChecked = filterByItemDataModel.isChecked

                    binding.filterCheckBoxBtn.setOnCheckedChangeListener { _, isChecked ->
                        filterByItemDataModel.isChecked = isChecked
                        filteredData = Utils.processCheckBoxItems(
                            filterByName, isChecked, filterByItemDataModel.itemName.toString()
                        )
                        filterByData.invoke(filteredData)
                    }
                }
            }
        }
    }
}

3. 优化Fragment中的数据传递

确保Fragment传递正确的数据源给Adapter,避免重复创建数据:

private fun setFilterByDataRecyclerView(
    filterByTimeList: ArrayList<FilterByItemDataModel>, 
    filterName: String
) {
    // 直接使用传入的filterByTimeList,而非重新生成
    filterByItemAdapter.setFilterByDataList(filterByTimeList, filterName)
    dialogFilterLayoutBinding.filterItemRecyclerView.adapter = filterByItemAdapter
}

关键说明

  • 用选中位置控制RadioButton状态,统一管理单选逻辑,避免每个数据项状态不一致。
  • 点击RadioButton时遍历数据源,将所有项的isChecked设为false,再将当前项设为true,最后调用notifyDataSetChanged()刷新UI。
  • 移除Item内的RadioGroup,因为它只能管理同一布局内的RadioButton,无法跨RecyclerView Item实现互斥。

内容的提问来源于stack exchange,提问作者S S

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 01:09:51