我正在尝试material3,但无法显示我的snackbar。这段代码在material2中有效。当调用小吃栏时,该列会像我预期的那样向下移动,但它非常简短,比短期小吃栏短得多,并且没有任何消息。
@Composable
fun Snackbar(snackbarHostState: SnackbarHostState) {
SnackbarHost(
hostState = snackbarHostState,
snackbar = { snackbarData: SnackbarData ->
Card(
shape = RoundedCornerShape(10.dp),
modifier = Modifier
.padding(20.dp)
.wrapContentSize()
) {
Text(text = snackbarData.visuals.message, fontSize = 30.sp)
}
}
)
}
@Composable
fun LaunchSnackbar (snackbarHostState: SnackbarHostState, message: String) {
LaunchedEffect(true) {
snackbarHostState.showSnackbar(message = message)
}
}
val snackbarHostState = remember { SnackbarHostState() }
Snackbar(snackbarHostState)
LaunchSnackbar(snackbarHostState = snackbarHostState, message = "Incorrect")
看起来我唯一需要改变的是
snackbarData.message
snackbarData.visual.message
不知道还有什么问题。
请分享您的
Scaffold
的代码。我想看看你如何将 SnackBarHost
放在 Scaffold
中。
如果您查看文档,我们会看到:
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Scaffold(
snackbarHost = { SnackbarHost(snackbarHostState) },
content = {
…
scope.launch {
snackbarHostState.showSnackbar(…)
}
}
)
这告诉我,从下面的两行(来自您发布的代码)
Snackbar(snackbarHostState)
LaunchSnackbar(snackbarHostState = snackbarHostState, message = "Incorrect")
我们应该将第一行替换为
Scaffold
,您应该将 Snackbar(snackbarHostState)
传递给该行。
因此,如果我重复文档代码,它将看起来像:
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Scaffold(
snackbarHost = { Snackbar(snackbarHostState) },
content = {
…
scope.launch {
snackbarHostState.showSnackbar(…)
}
}
)
LaunchSnackbar(snackbarHostState = snackbarHostState, message = "Incorrect")
我也遇到过类似的问题,协程在重组时被取消,而小吃店的消失速度比指定的持续时间要快。我发现有效的解决方案是在 NavHost 周围创建一个脚手架,并将 SnackbarHost 分配给这个脚手架,在这个可组合项中执行启动的效果。
我还遇到的一个问题是忘记,如果您的小吃栏消息状态相同(如在同一条消息中),则 LaunchedEffect 将不会执行,因为从技术上讲您的消息状态没有改变。要以简单的方式解决此问题,请将消息类型修改为数据类,该数据类具有消息发送到消息共享流上的时间时间戳。
@Composable
fun NavHostComposable(
viewModel: ViewModel
) {
val navController = rememberNavController()
val snackbarHostState = remember{SnackbarHostState()}
val snackbarMessages by viewModel.snackbarMessages.collectAsState(initial = null)
LaunchedEffect(key1 = snackbarMessages) {
snackbarMessages?.let { snackBarMessage ->
//Show snackbar message on every non-null value
snackbarHostState.showSnackbar(
message = snackBarMessage.message,
duration = SnackbarDuration.Short
)
}
}
Scaffold(
snackbarHost = { SnackbarHost(snackbarHostState) },
) { innerPadding ->
NavHost(
modifier = Modifier.padding(innerPadding ),
navController = navController,
...
) {
...
}
}
}
接受的答案中的代码有效,但显示 linter 错误 CoroutineCreationDuringComposition,“调用启动应该发生在 LaunchedEffect 内部,而不是组合内部”。
LaunchedEffect 文档位于 https://developer.android.com/jetpack/compose/side-effects#launchedeffect 显示的代码略有不同,linter 也将其评估为正确,`
// If the UI state contains an error, show snackbar
if (state.hasError) {
// `LaunchedEffect` will cancel and re-launch if
// `scaffoldState.snackbarHostState` changes
LaunchedEffect(snackbarHostState) {
// Show snackbar using a coroutine, when the coroutine is cancelled the
// snackbar will automatically dismiss. This coroutine will cancel whenever
// `state.hasError` is false, and only start when `state.hasError` is true
// (due to the above if-check), or if `scaffoldState.snackbarHostState` changes.
snackbarHostState.showSnackbar(
message = "Error message",
actionLabel = "Retry message"
)
}
}
Scaffold(
snackbarHost = {
SnackbarHost(hostState = snackbarHostState)
}
) { contentPadding ->
// ...
}`