In modern Android app development with Jetpack Compose, providing feedback to users is essential for a good user experience. Two common ways to provide feedback are using Snackbars and Toasts. While Toasts are straightforward, Snackbars in Compose offer more interactive capabilities and can be elegantly integrated into your UI.
What are Snackbars and Toasts?
- Toasts: Simple, non-interactive messages displayed briefly on the screen. They are typically used for quick notifications that don’t require user interaction.
- Snackbars: Provide more interactive feedback, typically appearing at the bottom of the screen. They can include an action button for the user to interact with.
Why Use Snackbars over Toasts in Compose?
- Interactive: Snackbars can include an action button for users.
- Integration: Easier to integrate into Compose’s declarative UI paradigm.
- Contextual: They provide feedback within the UI’s context.
How to Implement Toasts in Jetpack Compose
Toasts in Jetpack Compose are similar to traditional Android development. You use the Toast.makeText()
method within your composable function.
Step 1: Basic Toast Implementation
import android.content.Context
import android.widget.Toast
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
@Composable
fun ToastExample() {
val context = LocalContext.current
Button(onClick = {
Toast.makeText(context, "This is a Toast!", Toast.LENGTH_SHORT).show()
}) {
Text("Show Toast")
}
}
@Preview(showBackground = true)
@Composable
fun PreviewToastExample() {
ToastExample()
}
Explanation:
LocalContext.current
provides the current context.- The
Button
triggers a Toast when clicked. Toast.makeText()
creates and displays the Toast message.
How to Implement Snackbars in Jetpack Compose
Implementing Snackbars in Jetpack Compose requires the use of SnackbarHost
and SnackbarHostState
. The SnackbarHostState
manages the showing and dismissing of Snackbars, while SnackbarHost
is a composable that displays the Snackbar when it is shown.
Step 1: Add Dependencies
Ensure you have the Material 3 dependencies in your build.gradle
file:
dependencies {
implementation("androidx.compose.material3:material3:1.1.1") // or newer
}
Step 2: Implement Snackbar with SnackbarHostState
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import kotlinx.coroutines.launch
import androidx.compose.foundation.layout.Box
import androidx.compose.ui.Alignment
@Composable
fun SnackbarExample() {
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Box(
contentAlignment = Alignment.Center
) {
Button(onClick = {
scope.launch {
snackbarHostState.showSnackbar(
message = "This is a Snackbar!",
actionLabel = "Dismiss",
duration = SnackbarDuration.Short
)
}
}) {
Text("Show Snackbar")
}
SnackbarHost(hostState = snackbarHostState, modifier = Modifier.align(Alignment.BottomCenter))
}
}
@Preview(showBackground = true)
@Composable
fun PreviewSnackbarExample() {
SnackbarExample()
}
Explanation:
SnackbarHostState
is used to manage the Snackbar’s visibility and lifecycle.rememberCoroutineScope()
creates a CoroutineScope tied to the composable’s lifecycle.scope.launch
launches a coroutine to show the Snackbar.snackbarHostState.showSnackbar()
displays the Snackbar with a message and an optional action label.SnackbarHost
is the composable that actually renders the Snackbar on the screen, listening to thesnackbarHostState
.
Step 3: Adding an Action to the Snackbar
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import kotlinx.coroutines.launch
import androidx.compose.foundation.layout.Box
import androidx.compose.ui.Alignment
@Composable
fun SnackbarWithActionExample() {
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Box(
contentAlignment = Alignment.Center
) {
Button(onClick = {
scope.launch {
val result = snackbarHostState.showSnackbar(
message = "This is a Snackbar with an Action!",
actionLabel = "Undo",
duration = SnackbarDuration.Indefinite
)
when (result) {
SnackbarResult.ActionPerformed -> {
// Handle the action (e.g., undo something)
println("Undo action performed!")
}
SnackbarResult.Dismissed -> {
// Handle the dismissal
println("Snackbar dismissed.")
}
}
}
}) {
Text("Show Snackbar with Action")
}
SnackbarHost(hostState = snackbarHostState, modifier = Modifier.align(Alignment.BottomCenter))
}
}
@Preview(showBackground = true)
@Composable
fun PreviewSnackbarWithActionExample() {
SnackbarWithActionExample()
}
Explanation:
- The
showSnackbar
function returns aSnackbarResult
indicating whether the action was performed or the Snackbar was dismissed. - Based on the
SnackbarResult
, you can execute different logic, such as undoing an action whenActionPerformed
is returned. SnackbarDuration.Indefinite
makes the Snackbar remain on the screen until an action is taken or it is manually dismissed.
Advanced Snackbar Usage
Customizing the Snackbar
You can customize the appearance of the Snackbar by providing a custom SnackbarData
to the SnackbarHost
. Here is an example that modifies the color of the text and action:
import androidx.compose.foundation.layout.Box
import androidx.compose.material3.Button
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import kotlinx.coroutines.launch
import androidx.compose.material3.Snackbar
import androidx.compose.material3.MaterialTheme
@Composable
fun CustomSnackbarExample() {
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Box(
contentAlignment = Alignment.Center
) {
Button(onClick = {
scope.launch {
val result = snackbarHostState.showSnackbar(
message = "This is a Customized Snackbar!",
actionLabel = "Okay",
duration = SnackbarDuration.Short
)
when (result) {
SnackbarResult.ActionPerformed -> {
// Handle action performed
}
SnackbarResult.Dismissed -> {
// Handle dismissed
}
}
}
}) {
Text("Show Customized Snackbar")
}
SnackbarHost(hostState = snackbarHostState) { data ->
Snackbar(
snackbarData = data,
contentColor = Color.Yellow, // Custom content color
actionColor = Color.Green // Custom action color
)
}
}
}
@Preview(showBackground = true)
@Composable
fun PreviewCustomSnackbarExample() {
CustomSnackbarExample()
}
In this example, we define a custom Snackbar
within the SnackbarHost
, which allows us to set custom colors for the text (contentColor
) and the action (actionColor
).
Conclusion
Jetpack Compose offers excellent ways to provide feedback to users through Toasts and Snackbars. While Toasts are simple for quick, non-interactive messages, Snackbars provide more flexibility and interactivity, fitting perfectly within Compose’s modern UI paradigm. By leveraging SnackbarHost
and SnackbarHostState
, you can easily integrate Snackbars into your Composable functions to enhance the user experience.