You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose多ModalBottomSheet状态变更时未更新问题

问题原因

你把底部弹窗的Composable内容存进了mutableStateOf类型的bottomSheetContent变量中,点击按钮赋值时,lambda捕获的是赋值当下的screenState值。后续screenState更新时,已经存入状态的Composable lambda不会自动订阅状态变更,也不会重新生成新的实例,因此弹窗内部拿不到最新的选中状态,不会触发重组。
主页面的代码直接在MainScreen的Composition作用域中读取screenState,状态变化时会正常触发重组,因此能显示最新值。

修复方案

优先推荐第一种实现方式,逻辑更清晰,也符合Compose状态驱动UI的设计原则。

方案1:用状态标记弹窗类型,直接在sheetContent中渲染UI

  1. 首先定义密封类标记当前要展示的弹窗类型:
sealed class BottomSheetType {
    object None : BottomSheetType()
    object First : BottomSheetType()
    object Second : BottomSheetType()
}
  1. 替换原来存储Composable内容的状态,改为存储当前弹窗类型:
// 替换掉原来的bottomSheetContent状态
var currentBottomSheet by remember {
    mutableStateOf<BottomSheetType>(BottomSheetType.None)
}
  1. 修改ModalBottomSheetLayout的sheetContent逻辑,直接根据当前弹窗类型渲染对应内容,不要使用预存的Composable lambda:
sheetContent = {
    Box(
        modifier = Modifier.defaultMinSize(minHeight = 1.dp)
    ) {
        when (currentBottomSheet) {
            BottomSheetType.First -> FirstBottomSheet(
                selectedText = screenState.selectedTextFromFirstBottomSheet,
                onSelected = { text ->
                    viewModel.onEvent(MainScreenEvent.OnFirstBottomSheetSelectedTextChanged(text))
                },
                textList = screenState.firstBottomSheetTextList
            )
            BottomSheetType.Second -> SecondBottomSheet(
                selectedText = screenState.selectedTextFromSecondBottomSheet,
                onSelected = { text ->
                    viewModel.onEvent(MainScreenEvent.OnSecondBottomSheetSelectedTextChanged(text))
                },
                textList = screenState.secondBottomSheetTextList
            )
            BottomSheetType.None -> Unit
        }
    }
}
  1. 修改两个按钮的点击逻辑,不再赋值Composable内容,只更新当前弹窗类型再唤起弹窗:
// 第一个按钮点击逻辑
Button(onClick = {
    currentBottomSheet = BottomSheetType.First
    scope.launch {
        bottomSheetState.show()
    }
}, modifier = Modifier.padding(16.dp)) {
    Text(text = " Open First BottomSheet")
}

// 第二个按钮点击逻辑
Button(onClick = {
    currentBottomSheet = BottomSheetType.Second
    scope.launch {
        bottomSheetState.show()
    }
}, modifier = Modifier.padding(16.dp)) {
    Text(text = " Open Second BottomSheet")
}

可以额外加一个状态监听,弹窗隐藏时重置状态:

LaunchedEffect(bottomSheetState.currentValue) {
    if (bottomSheetState.currentValue == ModalBottomSheetValue.Hidden) {
        currentBottomSheet = BottomSheetType.None
    }
}

方案2:监听状态变化,同步更新存储的Composable内容

如果你一定要保留存储Composable实例的写法,需要在screenState变化时重新给bottomSheetContent赋值,保证lambda捕获的是最新状态。这种写法冗余度更高,不推荐使用:

// 同样需要先定义弹窗类型状态
var currentBottomSheet by remember {
    mutableStateOf<BottomSheetType>(BottomSheetType.None)
}

// 监听screenState变化,同步更新弹窗内容
LaunchedEffect(screenState, currentBottomSheet) {
    bottomSheetContent = when (currentBottomSheet) {
        BottomSheetType.First -> {
            {
                FirstBottomSheet(
                    selectedText = screenState.selectedTextFromFirstBottomSheet,
                    onSelected = { text ->
                        viewModel.onEvent(MainScreenEvent.OnFirstBottomSheetSelectedTextChanged(text))
                    },
                    textList = screenState.firstBottomSheetTextList
                )
            }
        }
        BottomSheetType.Second -> {
            {
                SecondBottomSheet(
                    selectedText = screenState.selectedTextFromSecondBottomSheet,
                    onSelected = { text ->
                        viewModel.onEvent(MainScreenEvent.OnSecondBottomSheetSelectedTextChanged(text))
                    },
                    textList = screenState.secondBottomSheetTextList
                )
            }
        }
        BottomSheetType.None -> null
    }
}

按钮点击逻辑和方案1一致,只更新currentBottomSheet再唤起弹窗即可。


内容的提问来源于stack exchange,提问作者Teo Coding

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 22:03:22