如何在 Jetpack Compose 中使用 onclick 按钮显示小吃栏

mik*_* so 36 android android-jetpack-compose

我想在 Jetpack Compose 中显示带有 onclick 按钮的小吃栏
我尝试过这个

Button(onClick = {
    Snackbar(action = {}) {
        Text("hello")
    }
} 
Run Code Online (Sandbox Code Playgroud)

但是 AS 说“@Composable 调用只能在 @Composable 函数的上下文中发生”,
你能给我一个好的程序吗?
我希望它可以在 Button.onclick() 中运行

Bar*_*ski 45

你需要两件事:

  1. SnackbarHostState- 这将管理您的状态Snackbar您通常会从 获得ScaffoldState
  2. CoroutineScope- 这将对showing您负责Snackbar

@Composable
fun SnackbarDemo() {
  val scaffoldState = rememberScaffoldState() // this contains the `SnackbarHostState`
  val coroutineScope = rememberCoroutineScope()

  Scaffold(
        modifier = Modifier,
        scaffoldState = scaffoldState // attaching `scaffoldState` to the `Scaffold`
    ) {
        Button(
            onClick = {
                coroutineScope.launch { // using the `coroutineScope` to `launch` showing the snackbar
                    // taking the `snackbarHostState` from the attached `scaffoldState`
                    val snackbarResult = scaffoldState.snackbarHostState.showSnackbar(
                        message = "This is your message",
                        actionLabel = "Do something."
                    )
                    when (snackbarResult) {
                        Dismissed -> Log.d("SnackbarDemo", "Dismissed")
                        ActionPerformed -> Log.d("SnackbarDemo", "Snackbar's button clicked")
                    }
                }
            }
        ) {
            Text(text = "A button that shows a Snackbar")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

例子

  • RememberScaffoldState 在 Material 3 中不再可用。在此处查看新的实现:https://developer.android.com/reference/kotlin/androidx/compose/material3/package-summary#Snackbar(androidx.compose.ui.Modifier, kotlin.Function0,kotlin.Function0,kotlin.Boolean,androidx.compose.ui.graphics.Shape,androidx.compose.ui.graphics.Color,androidx.compose.ui.graphics.Color,androidx.compose.ui.graphics.颜色,androidx.compose.ui.graphics.Color,kotlin.Function0) (3认同)

bru*_*max 15

如果您使用新的 Material3,Scaffold 中会有新字段:“snackbarHost”

val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()

Scaffold(
  snackbarHost = { SnackbarHost(snackbarHostState) },
  ...

            // for showing snackbar in onClick for example:
            scope.launch {
                snackbarHostState.showSnackbar(
                    "Snackbar Test"
                )
            }
Run Code Online (Sandbox Code Playgroud)


小智 7

在 Bartek 的答案的基础上,您还可以使用Compose 的副作用。那么您就不必管理CoroutineScope本身。

由于Composables其本身应该是无副作用的,因此建议使用,Compose's Effect APIs以便以可预测的方式执行这些副作用。

在您的特定情况下,您可以使用LaunchedEffect API在可组合项范围内运行挂起函数。示例代码如下所示:

@Composable
fun SnackbarDemo() {
    val scaffoldState = rememberScaffoldState() // this contains the `SnackbarHostState`
    val (showSnackBar, setShowSnackBar) = remember {
        mutableStateOf(false)
    }
    if (showSnackBar) {
        LaunchedEffect(scaffoldState.snackbarHostState) {
            // Show snackbar using a coroutine, when the coroutine is cancelled the
            // snackbar will automatically dismiss. This coroutine will cancel whenever
            // `showSnackBar` is false, and only start when `showSnackBar` is true
            // (due to the above if-check), or if `scaffoldState.snackbarHostState` changes.
            val result = scaffoldState.snackbarHostState.showSnackbar(
                message = "Error message",
                actionLabel = "Retry message"
            )
            when (result) {
                SnackbarResult.Dismissed -> {
                    setShowSnackBar(false)
                }
                SnackbarResult.ActionPerformed -> {
                    setShowSnackBar(false)
                    // perform action here
                }
            }
        }
    }
    Scaffold(
        modifier = Modifier,
        scaffoldState = scaffoldState // attaching `scaffoldState` to the `Scaffold`
    ) {
        Button(
            onClick = {
                setShowSnackBar(true)
            }
        ) {
            Text(text = "A button that shows a Snackbar")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Far*_*han 7

Material3 中带有操作的 Snackbar

@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun DemoSnackBar() {
    val snackBarHostState = remember {
        SnackbarHostState()
    }
    val coroutineScope = rememberCoroutineScope()
    Scaffold(content = {
        Column(
            modifier = Modifier.fillMaxSize(),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Button(onClick = {
                coroutineScope.launch {

                    val snackBarResult = snackBarHostState.showSnackbar(
                        message = "Snackbar is here",
                        actionLabel = "Undo",
                        duration = SnackbarDuration.Short
                    )
                    when (snackBarResult) {
                        SnackbarResult.ActionPerformed -> {
                            Log.d("Snackbar", "Action Performed")
                        }
                        else -> {
                            Log.d("Snackbar", "Snackbar dismissed")
                        }
                    }
                }

            }) {
                Text(text = "Show Snack Bar", color = Color.White)
            }
        }
    }, snackbarHost = { SnackbarHost(hostState = snackBarHostState) })
}
Run Code Online (Sandbox Code Playgroud)


and*_*v71 5

以防万一您需要一个小吃栏作为单独的函数来使用自定义参数调用其他屏幕,并且不使用脚手架,我在下面使用它。

该参数openSnackbar: (Boolean) -> Unit用于重置打开条件 var openMySnackbar by remember { mutableStateOf(false) }并允许其他时间打开snackbar。

    @Composable
    fun SnackbarWithoutScaffold(
        message: String,
        showSb: Boolean,
        openSnackbar: (Boolean) -> Unit
    ) {
    
        val snackState = remember { SnackbarHostState() }
        val snackScope = rememberCoroutineScope()
    
        SnackbarHost(
            modifier = Modifier,
            hostState = snackState
        ){
            Snackbar(
                snackbarData = it,
                backgroundColor = Color.White,
                contentColor = Color.Blue
            )
        }
    
    
        if (showSb){
            LaunchedEffect(Unit) {
                snackScope.launch { snackState.showSnackbar(message) }
                openSnackbar(false)
            }
   
        }
    
    
    }
Run Code Online (Sandbox Code Playgroud)

并像这样使用:

@Composable fun MyScreen() {

var openMySnackbar by remember { mutableStateOf(false)  }
var snackBarMessage by remember { mutableStateOf("") }

Column() {

    Button(
        shape = RoundedCornerShape(50.dp),
        onClick = {
            openMySnackbar = true
            snackBarMessage = "Your message"
        },
    ) {
        Text(text = "Open Snackbar")
    }

    SnackbarWithoutScaffold(snackBarMessage, openMySnackbar, , {openMySnackbar = it})
}
Run Code Online (Sandbox Code Playgroud)

}