Kotlin中RecyclerView内Radio Button选中状态异常问题
问题根源
- 每个列表项的RadioButton都被包裹在独立的
RadioGroup中,系统无法跨Item管理单选互斥逻辑。 - 点击RadioButton时未更新数据源的选中状态,也未通知Adapter刷新UI。
- 没有维护全局选中标记,无法自动取消其他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
相关产品推荐
相关产品推荐

