android 使用脚手架在Material Design 3中显示Snackbar

bq3bfh9z  于 2023-04-28  发布在  Android
关注(0)|答案(3)|浏览(267)

决定在我的新Jetpack Compose项目中尝试***Material Design 3***。一切都很舒适,直到我需要展示一个Snackbar时,我撞到了墙上。
在***MD2***中,这非常简单,你可以在协程范围内使用SnackbarHostState.showSnackbar()函数在脚手架中显示snackbar。我观察到你只需要从Material Library导入androidx.compose.material.rememberScaffoldState

import androidx.compose.material.rememberScaffoldState

@Composable
fun MyScreenInMaterial2() {
    val scaffoldState = rememberScaffoldState()
}

当我在***MD3***中尝试相同的操作时,rememberScaffoldState()函数无法解析。

对于那些在MD3世界潜水的人来说,如何在脚手架中显示Snackbar?我已经检查了文档和在线资源,但我还没有找到解决方案。

wvmv3b1j

wvmv3b1j1#

这里有一个来自官方文档的示例。

val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Scaffold(
    snackbarHost = { SnackbarHost(snackbarHostState) },
    floatingActionButton = {
        var clickCount by remember { mutableStateOf(0) }
        ExtendedFloatingActionButton(
            onClick = {
                // show snackbar as a suspend function
                scope.launch {
                    snackbarHostState.showSnackbar(
                        "Snackbar # ${++clickCount}"
                    )
                }
            }
        ) { Text("Show snackbar") }
    },
    content = { innerPadding ->
        Text(
            text = "Body content",
            modifier = Modifier.padding(innerPadding).fillMaxSize().wrapContentSize()
        )
    }
)
ltskdhd1

ltskdhd12#

如果你使用CoroutineScope,你会得到一个警告,说CoroutineCreationDuringComposition
官方文档建议使用LaunchedEffect来避免这种副作用。
因此,建议的代码看起来像这样:

val snackbarHostState = remember { SnackbarHostState() }

Scaffold(
    snackbarHost = { SnackbarHost(snackbarHostState) },
    floatingActionButton = {
        var clickCount by remember { mutableStateOf(0) }
        ExtendedFloatingActionButton(
            onClick = {
                LaunchedEffect(snackbarHostState) {
                    snackbarHostState.showSnackbar(
                        "Snackbar # ${++clickCount}"
                    )
                }
            }
        ) { Text("Show snackbar") }
    },
    content = { innerPadding ->
        Text(
            text = "Body content",
            modifier = Modifier.padding(innerPadding).fillMaxSize().wrapContentSize()
        )
    }
)
dwthyt8l

dwthyt8l3#

在我的例子中,有一个编译错误:

@Composable invocations can only happen from the context of a @Composable function

当在onClickChip lambda内部调用LaunchedEffect时。
有一个替代选项,灵感来自这个answer
对于那些想要在lambda(w/o @Composable)中显示Compose Snackbar的用户

@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
@Composable
fun ScreenA() {
    val snackbarHostState = remember { SnackbarHostState() }
    val snackbarMessage = "Succeed!"
    val showSnackbar = remember { mutableStateOf(false) }

    LaunchedEffect(showSnackbar.value) {
        if (showSnackbar.value)
            snackbarHostState.showSnackbar(snackbarMessage)
    }
    Surface {
        Scaffold(
            snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
        ) {
            ChipIcon(
                text = "Click me: ${showSnackbar.value}",
                onClickChip = {
                    // unable to use LaunchedEffect in here
                    showSnackbar.value = !showSnackbar.value
                }
            )
        }
    }
}

// Custom Composable
@Composable
fun ChipIcon(
    text: String,
    onClickChip: () -> Unit, // no @Composable, unable to use LaunchedEffect in this lambda
) {
    Row(
        modifier = Modifier
            .clickable(
                enabled = true,
                onClick = {
                    onClickChip()
                }
            ),
    ) {
        Text(text = text)
    }
}

LaunchedEffect上观察showSnackbar.value的更改以取消/重新启动,如果是showSnackbar.value == true,则显示snackbar,否则不执行任何操作

相关问题