Reputation: 8196
I'm facing an issue with Android Jetpack Compose Snackbar in my application. I have a LazyColumn where each row is a SwipeToDismiss composable. On each swipe, I remove the row and show a Snackbar. However, if I swipe rows very frequently, a queue of Snackbars is created, and they appear one by one. I want to modify this behavior so that only the latest Snackbar is shown, and it immediately closes the previous one.
val scaffoldState = rememberScaffoldState()
LaunchedEffect(key1 = true) {
viewModel.uiEvent.collect { event ->
when (event) {
is UiEvent.ShowSnackBar -> {
val snackbarResult = scaffoldState.snackbarHostState.showSnackbar(
message = event.message,
actionLabel = event.action
)
when (snackbarResult) {
SnackbarResult.Dismissed -> {}
SnackbarResult.ActionPerformed -> viewModel.onEvent(MessageListEvent.OnUndoDeleteClick)
}
}
else -> Unit
}
}
}
Upvotes: 5
Views: 2673
Reputation: 3620
I would suggest you cancel the previous snackBar before show next.
the reason why we could do that is SnackbarHostState has a publish property: currentSnackbarData
. it is the The current SnackbarData being shown by the SnackbarHost, of null if none.
scaffoldState.currentSnackbarData
then, call dismiss method
next show the new snackbar
scaffoldState.currentSnackbarData.dismiss()
so the final answer is:
val scaffoldState = rememberScaffoldState()
LaunchedEffect(key1 = true) {
viewModel.uiEvent.collect { event ->
when (event) {
is UiEvent.ShowSnackBar -> {
scaffoldState.currentSnackbarData.dismiss()
val snackbarResult = scaffoldState.snackbarHostState.showSnackbar(
message = event.message,
actionLabel = event.action
)
when (snackbarResult) {
SnackbarResult.Dismissed -> {}
SnackbarResult.ActionPerformed -> viewModel.onEvent(MessageListEvent.OnUndoDeleteClick)
}
}
else -> Unit
}
}
}
Upvotes: 3
Reputation: 4256
You could try something like:
val uiEvent = viewModel.uiEvent.collectAsStateWithLifecycle()
LaunchedEffect(uiEvent.value) {
when (val event = uiEvent.value) {
is UiEvent.ShowSnackBar -> {
val snackbarResult = scaffoldState.snackbarHostState.showSnackbar(
message = event.message,
actionLabel = event.action
)
when (snackbarResult) {
SnackbarResult.Dismissed -> {}
SnackbarResult.ActionPerformed -> viewModel.onEvent(MessageListEvent.OnUndoDeleteClick)
}
}
else -> Unit
}
}
This way, when uiEvent.value
changes, LaunchedEffect
will cancel the previous coroutine and its snackbar will be automatically dismissed.
Upvotes: 0