Jetpack Compose MultiComboBox组件onExpandedChange异常求助
问题原因分析
你遇到的问题核心在于**ExposedDropdownMenuBox的onExpandedChange lambda无法捕获到currentlySelected的最新值**:
onExpandedChange是在组件首次组合时被创建并传递给ExposedDropdownMenuBox的,后续currentlySelected的变化(比如选择/取消选项)不会触发ExposedDropdownMenuBox的重组,因此该lambda一直使用初始化时捕获的currentlySelected初始值。- 而
ExposedDropdownMenu的onDismissRequest会随着currentlySelected的变化(选项操作会触发组件重组)重新生成,所以能拿到最新的选中状态,这就是点击外部区域收起时功能正常的原因。
另外,你的selectedSummary基于父组件传入的selectedIds生成,无法实时反映用户的临时选择,属于体验上的小瑕疵。
修复方案
- 使用
rememberUpdatedState包装currentlySelected,确保onExpandedChange始终能访问到最新的选中状态。 - 将
selectedSummary的生成逻辑改为基于当前选中状态,让显示内容实时同步用户操作。
修改后的完整代码
data class ComboOption( override val text: String, val id: Int, ) : SelectableOption interface SelectableOption { val text: String } @Composable fun MultiComboBox( labelText: String, options: List<ComboOption>, onOptionsChosen: (Set<ComboOption>) -> Unit, modifier: Modifier = Modifier, selectedIds: Set<Int> = emptySet(), ) { var expanded by remember { mutableStateOf(false) } val isEnabled by rememberUpdatedState { options.isNotEmpty() } var currentlySelected by remember(options, selectedIds) { mutableStateOf(options.filter { it.id in selectedIds }.toSet()) } // 保存最新选中状态的引用,确保lambda能拿到最新值 val latestSelected by rememberUpdatedState(currentlySelected) ExposedDropdownMenuBox( expanded = expanded, onExpandedChange = { if (isEnabled()) { expanded = !expanded if (!expanded) { onOptionsChosen(latestSelected) } } }, modifier = modifier, ) { // 基于当前选中状态生成显示文本,实时同步用户操作 val selectedSummary = when (latestSelected.size) { 0 -> "" 1 -> latestSelected.first().text else -> "Wybrano ${latestSelected.size}" } TextField( enabled = isEnabled(), modifier = Modifier.menuAnchor(), readOnly = true, value = selectedSummary, onValueChange = {}, label = { Text(text = labelText) }, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, colors = ExposedDropdownMenuDefaults.textFieldColors(), ) ExposedDropdownMenu( expanded = expanded, onDismissRequest = { expanded = false onOptionsChosen(latestSelected) }, ) { options.forEach { option -> DropdownMenuItem( text = { Row(verticalAlignment = Alignment.CenterVertically) { Checkbox( checked = option in latestSelected, onCheckedChange = { newCheckedState -> currentlySelected = if (newCheckedState) { currentlySelected + option } else { currentlySelected - option } }, ) Text(text = option.text) } }, onClick = { currentlySelected = if (option in latestSelected) { currentlySelected - option } else { currentlySelected + option } }, contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding, ) } } } }
额外说明
rememberUpdatedState的作用是在组合中保存最新的变量引用,即使持有该引用的lambda没有被重新创建,也能访问到最新的值。- 把
selectedSummary改为基于latestSelected后,用户选择选项时文本框会实时更新,无需等到收起下拉框,提升了交互体验。
内容的提问来源于stack exchange,提问作者KarolKVimn
相关产品推荐
相关产品推荐

