Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to show snackbar with a button onclick in Jetpack Compose

I want to show snackbar with a button onclick in Jetpack Compose
I tried this

Button(onClick = {
    Snackbar(action = {}) {
        Text("hello")
    }
} 

But AS said "@Composable invocations can only happen from the context of a @Composable function"
Shall you give me a nice program.
I wish it can run in Button.onclick()

like image 294
mike so Avatar asked Aug 24 '21 14:08

mike so


People also ask

How do you show snackbar on button click in jetpack compose?

You'll need two things: SnackbarHostState - which will manage the state of your Snackbar (you would usually get that from the ScaffoldState ) CoroutineScope - which will be responsible for showing your Snackbar.

How do you display snackbar in jetpack compose?

Show or hide snackbar By clicking the floating button, a snackbar with the text button appeared.

How do I use snackbar?

This example demonstrates how do I use snackBar in android. Step 1 − Create a new project in Android Studio, go to File ⇒ New Project and fill all required details to create a new project. Step 2 − Add the following code to res/layout/activity_main. xml.

What is LazyColumn in jetpack compose?

A LazyColumn is a vertically scrolling list that only composes and lays out the currently visible items. It's similar to a Recyclerview in the classic Android View system.


2 Answers

You'll need two things:

  1. SnackbarHostState - which will manage the state of your Snackbar (you would usually get that from the ScaffoldState)
  2. CoroutineScope - which will be responsible for showing your 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")
        }
    }
}

example

like image 177
Bartek Lipinski Avatar answered Oct 21 '22 15:10

Bartek Lipinski


Building on Bartek's answer you can also use Compose's side-effects. Then you don't have to manage the CoroutineScope itself.

Since Composables itself should be side-effect free, it is recommended to make use of Compose's Effect APIs so that those side effects are executed in a predictable manner.

In your specific case you can use the LaunchedEffect API to run suspend functions in the scope of a composable. The example code would look like the following:

@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")
        }
    }
}
like image 27
jendress Avatar answered Oct 21 '22 14:10

jendress