RecyclerView中实现单选Checkbox遇选中错误问题求助
RecyclerView单选Checkbox选中错误问题修正
问题说明
需要在RecyclerView中实现单选Checkbox功能,不想调用notifyDataSetChanged,但尝试代码后出现选中状态错误的问题。
原问题代码
import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.CheckBox import android.widget.ImageView import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import com.tps.challenge.R import com.tps.challenge.domain.Store import com.tps.challenge.ui.Event class StoreFeedAdapter( private val stores: List<Store>, private val itemClickListener: (Event<Store>) -> Unit ): RecyclerView.Adapter<StoreItemViewHolder>() { private var prevSelectedPos: Int = 0 private var currSelectedPos: Int = 0 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StoreItemViewHolder { return StoreItemViewHolder( LayoutInflater.from(parent.context) .inflate(R.layout.item_store, parent, false) ).also { viewHolder -> viewHolder.storeImage.setOnClickListener { val selectedStore = stores[viewHolder.adapterPosition] itemClickListener.invoke( Event(selectedStore) ) } viewHolder.checkbox.setOnClickListener { currSelectedPos = viewHolder.adapterPosition notifyItemChanged(prevSelectedPos) notifyItemChanged(currSelectedPos) prevSelectedPos = currSelectedPos } } } override fun onBindViewHolder(holder: StoreItemViewHolder, position: Int) { holder.checkbox.isSelected = currSelectedPos == position val store = stores[position] with(holder.itemView) { findViewById<TextView>(R.id.name).text = store.name findViewById<TextView>(R.id.description).text = store.desc Glide.with(holder.itemView.context) .load(store.coverImgUrl) .into(holder.storeImage) } } override fun getItemCount(): Int { return stores.size } } class StoreItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val storeImage: ImageView = itemView.findViewById(R.id.iv_store) val checkbox: CheckBox = itemView.findViewById(R.id.cb_select) }
问题分析
- 初始值错误:
prevSelectedPos和currSelectedPos初始都设为0,会默认选中第0项,且未考虑无选中的场景。 - 状态设置错误:使用
isSelected控制CheckBox状态,CheckBox的勾选状态应由isChecked控制,两者属于不同概念。 - 点击逻辑缺陷:未处理点击已选中项的情况,冗余变量易导致状态混乱。
- ViewHolder复用问题:滚动时可能因状态绑定错误导致选中状态错乱。
修正后的代码
import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.CheckBox import android.widget.ImageView import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import com.tps.challenge.R import com.tps.challenge.domain.Store import com.tps.challenge.ui.Event class StoreFeedAdapter( private val stores: List<Store>, private val itemClickListener: (Event<Store>) -> Unit ): RecyclerView.Adapter<StoreItemViewHolder>() { // 初始设为-1表示无默认选中项,需默认选中可改为对应位置 private var selectedPos: Int = -1 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StoreItemViewHolder { return StoreItemViewHolder( LayoutInflater.from(parent.context) .inflate(R.layout.item_store, parent, false) ).also { viewHolder -> viewHolder.storeImage.setOnClickListener { val selectedStore = stores[viewHolder.adapterPosition] itemClickListener.invoke(Event(selectedStore)) } viewHolder.checkbox.setOnClickListener { val position = viewHolder.adapterPosition // 点击已选中项时取消选中 if (selectedPos == position) { selectedPos = -1 notifyItemChanged(position) } else { val oldSelectedPos = selectedPos selectedPos = position // 仅刷新状态变化的项,避免全局刷新 if (oldSelectedPos != -1) { notifyItemChanged(oldSelectedPos) } notifyItemChanged(selectedPos) } } } } override fun onBindViewHolder(holder: StoreItemViewHolder, position: Int) { // 用isChecked正确绑定CheckBox勾选状态 holder.checkbox.isChecked = selectedPos == position val store = stores[position] with(holder.itemView) { findViewById<TextView>(R.id.name).text = store.name findViewById<TextView>(R.id.description).text = store.desc Glide.with(context) .load(store.coverImgUrl) .into(holder.storeImage) } } override fun getItemCount(): Int = stores.size } class StoreItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val storeImage: ImageView = itemView.findViewById(R.id.iv_store) val checkbox: CheckBox = itemView.findViewById(R.id.cb_select) }
修正要点
- 简化状态管理:用单个
selectedPos替代冗余变量,初始值设为-1表示无选中项。 - 修正状态绑定:将
isSelected改为isChecked,匹配CheckBox的勾选状态逻辑。 - 优化点击逻辑:支持点击已选中项取消选中,仅刷新状态变化的列表项,提升性能。
- 适配ViewHolder复用:在
onBindViewHolder中正确绑定状态,确保滚动时选中状态准确。
内容的提问来源于stack exchange,提问作者HukeLau_DABA
相关产品推荐
相关产品推荐

