如何借助SavedStateHandle为多个Chip创建单个ViewModel
解决多个Chip独立状态并通过SavedStateHandle持久化的方案
问题根源
当前ViewModel仅用单个CHECKED_STATE_KEY存储布尔值,所有Chip绑定同一状态,导致点击任意Chip时全量同步变化。要实现独立状态,需为每个Chip分配唯一状态键,通过SavedStateHandle存储多组键值对。
步骤1:修改ViewModel
将单个布尔状态改为Chip标识与选中状态的映射集合,同时提供单Chip状态的获取与更新方法:
class SavedStateViewModel(private val state: SavedStateHandle) : ViewModel() { // 用Map存储所有Chip的选中状态,初始为空即所有Chip默认未选中 private val chipStates = state.getStateFlow( key = CHIP_STATES_KEY, initialValue = emptyMap<String, Boolean>() ) // 获取指定Chip的选中状态,默认返回未选中 fun getChipState(chipKey: String): Boolean { return chipStates.value[chipKey] ?: false } // 更新指定Chip的选中状态 fun updateChipState(chipKey: String, isSelected: Boolean) { val currentStates = chipStates.value.toMutableMap() currentStates[chipKey] = isSelected state.set(CHIP_STATES_KEY, currentStates) } companion object { private const val CHIP_STATES_KEY = "chip_states" } }
步骤2:调整Chip调用逻辑
在AllAnimals组件中,每个Chip使用自身文本作为唯一标识键,绑定对应状态,并在点击时触发对应键的状态更新:
@SuppressLint("UnusedMaterialScaffoldPaddingParameter", "UnusedMaterial3ScaffoldPaddingParameter") @Composable fun AllAnimals( navController: NavController, viewModel: SavedStateViewModel = viewModel(), ) { // 收集Chip状态流,转为Composable可观测的状态 val chipStates by viewModel.chipStates.collectAsState() Scaffold( topBar = { TopAppBarAnimalsActivities( title = "Animals", buttonIcon = Icons.Filled.ArrowBack, onButtonClicked = { navController.popBackStack() } ) } ) { Column( verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { Column( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { Text( text = "What is your favourite animal?", fontSize = 25.sp, fontWeight = FontWeight.Bold, fontFamily = FontFamily.Default, color = DarkBlue ) Box( modifier = Modifier .fillMaxWidth(0.8F) .fillMaxHeight(0.93F), ) { Column( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.Top, horizontalAlignment = Alignment.Start ) { Spacer(modifier = Modifier.height(20.dp)) Row { Spacer(modifier = Modifier.width(5.dp)) SimpleChip( text = "Dog", isSelected = chipStates["Dog"] ?: false, onChecked = { isSelected -> viewModel.updateChipState("Dog", isSelected) }, ) Spacer(modifier = Modifier.width(5.dp)) SimpleChip( text = "Horse", isSelected = chipStates["Horse"] ?: false, onChecked = { isSelected -> viewModel.updateChipState("Horse", isSelected) }, ) Spacer(modifier = Modifier.width(5.dp)) SimpleChip( text = "Guinea Pig", isSelected = chipStates["GuineaPig"] ?: false, onChecked = { isSelected -> viewModel.updateChipState("GuineaPig", isSelected) }, ) } Spacer(modifier = Modifier.height(20.dp)) Row { Spacer(modifier = Modifier.width(5.dp)) SimpleChip( text = "Rabbit", isSelected = chipStates["Rabbit"] ?: false, onChecked = { isSelected -> viewModel.updateChipState("Rabbit", isSelected) }, ) Spacer(modifier = Modifier.width(5.dp)) SimpleChip( text = "Reptiles", isSelected = chipStates["Reptiles"] ?: false, onChecked = { isSelected -> viewModel.updateChipState("Reptiles", isSelected) }, ) Spacer(modifier = Modifier.width(5.dp)) SimpleChip( text = "Cats", isSelected = chipStates["Cats"] ?: false, onChecked = { isSelected -> viewModel.updateChipState("Cats", isSelected) }, ) } Spacer(modifier = Modifier.height(20.dp)) Row { Spacer(modifier = Modifier.width(5.dp)) SimpleChip( text = "Other", isSelected = chipStates["Other"] ?: false, onChecked = { isSelected -> viewModel.updateChipState("Other", isSelected) }, ) } } } } } } }
步骤3:保留原SimpleChip组件
你的SimpleChip组件无需修改,它已正确接收isSelected状态和点击回调,只需确保每个实例绑定不同的状态标识键即可:
@Composable fun SimpleChip( text: String, isSelected: Boolean, selectedColor: Color = Color.DarkGray, onChecked: (Boolean) -> Unit, ) { Surface( onClick = { onChecked(!isSelected) }, modifier = Modifier.padding(4.dp) .wrapContentSize() .border( width = 1.dp, color = if (isSelected) selectedColor else Color.LightGray, shape = RoundedCornerShape(20.dp) ), shape = RoundedCornerShape(16.dp), color = if (isSelected) LightGreen else Color.White, ) { Row( modifier = Modifier.padding(8.dp), horizontalArrangement = Arrangement.spacedBy(4.dp), verticalAlignment = Alignment.CenterVertically, ) { Text( text = text, fontSize = 18.sp, fontWeight = FontWeight.Bold, color = if (isSelected) Color.White else Color.Black, ) } } }
核心逻辑说明
- 用
Map<String, Boolean>存储所有Chip状态,每个Chip的唯一标识(如文本)作为键,确保状态独立隔离。 SavedStateHandle自动持久化该Map,配置变更(如屏幕旋转)后状态不会丢失。- 每个Chip点击时仅更新自身对应的键值对,不会影响其他Chip的选中状态。
内容的提问来源于stack exchange,提问作者Josef M
相关产品推荐
相关产品推荐

