BottomSheetFragment中onViewStateRestored触发时CardView背景不生效,选中状态丢失
问题根因
- 每次关闭BottomSheetFragment后,Fragment视图会走
onDestroyView销毁,你存储的b:CardView?是旧视图的控件实例,下次打开新视图重建后,这个引用已经失效,自然无法生效。 - 状态恢复逻辑写在
onViewStateRestored不适用于这个场景,且你在onViewCreated开头主动调用了RadioGroup.clearCheck(),直接清空了之前的选中状态。 - 仅存储View实例而非状态标识,视图重建后无法对应到新的控件。
具体修改方案
1. 调整存储变量,只存状态不存View
不要存储b、btn这类临时View实例,改为存储选中项的标识:
// 删除 private var b:CardView?=null、private var btn:Button? = null、private var cardView:CardView? = null 这三个变量 // 新增变量存储选中的卡片资源ID private var selectedCardId: Int? = null
2. 修改Card点击监听,存储选中ID
private val listener = View.OnClickListener { v-> val currentCard = v as CardView // 存储选中的卡片资源ID,而非View实例 selectedCardId = currentCard.id currentCard.setCardBackgroundColor(Color.BLACK) val linearLayout = currentCard.getChildAt(0) as LinearLayout val constrainLinearLayout = linearLayout.getChildAt(0) as ConstraintLayout val textView = constrainLinearLayout.getChildAt(0) as TextView textView.setTextColor(Color.WHITE) previousSelectRating = textView.text.toString() reset(currentCard.resources.getResourceEntryName(currentCard.id)) }
3. 把状态恢复逻辑移到onViewCreated末尾,替换无用的onViewStateRestored
删除你现在的onViewStateRestored方法所有代码,在onViewCreated的最后(dismiss点击事件后面)加恢复逻辑:
// 恢复CardView选中状态 selectedCardId?.let { cardId -> val selectedCard = view.findViewById<CardView>(cardId) ?: return@let selectedCard.setCardBackgroundColor(Color.BLACK) val linearLayout = selectedCard.getChildAt(0) as LinearLayout val constrainLinearLayout = linearLayout.getChildAt(0) as ConstraintLayout val textView = constrainLinearLayout.getChildAt(0) as TextView textView.setTextColor(Color.WHITE) reset(selectedCard.resources.getResourceEntryName(selectedCard.id)) } // 恢复RadioGroup选中状态,注意先临时移除监听器避免冲突 previousSelect?.let { selectId -> if (selectId != -1) { radioGroup1.setOnCheckedChangeListener(null) radioGroup2.setOnCheckedChangeListener(null) if (findViewById<RadioButton>(selectId)?.parent == radioGroup1) { radioGroup1.check(selectId) radioGroup2.clearCheck() } else { radioGroup2.check(selectId) radioGroup1.clearCheck() } radioGroup1.setOnCheckedChangeListener(listener1) radioGroup2.setOnCheckedChangeListener(listener2) changeTextColor(selectId, "White") } } previousSelectPrice?.let { priceId -> if (priceId != -1) { radioGroup3.setOnCheckedChangeListener(null) radioGroup3.check(priceId) radioGroup3.setOnCheckedChangeListener(listener3) changeTextColor(priceId, "White") } }
4. 调整开头的RadioGroup清空逻辑
把onViewCreated开头的radioGroup1.clearCheck()、radioGroup2.clearCheck()改为只有首次打开没有选中状态时才清空:
if (previousSelect == null) { radioGroup1.clearCheck() radioGroup2.clearCheck() } if (previousSelectPrice == null) { radioGroup3.clearCheck() }
补充说明
如果你每次打开底部弹窗都是新建Fragment实例,那成员变量会被重置,需要在新建实例时把之前的选中状态通过arguments传入,或者将选中状态存在宿主Activity/共享ViewModel中即可。
内容的提问来源于stack exchange,提问作者Souhil Hadj Habib
相关产品推荐
相关产品推荐

