My app has a lot of colour coding in it, and I can't figure out how to cleanly change the colour of a Snackbar action in a scaffold based on the action that shows the snackbar.
I have a composable, and inside there is a lazy list with an item that can be clicked. When you click it, that row has a specific colour associated with it.
Now, the click listener isn't a composable itself, I can't create a snackbar in it. I have to use the scaffolds snackbarHost
onClick {
scope.launch {
val snackbarResult = scaffoldState.snackbarHostState.showSnackbar(
message = "message",
actionLabel = "action"
)
when (snackbarResult) {
SnackbarResult.ActionPerformed -> do something
SnackbarResult.Dismissed -> do something
}
}
]
From here, I can't choose or set a colour.
In the scaffold, where I can make the snackbar, I can't get a colour back to it as it only has the snackbarData
Scaffold(
scaffoldState = scaffoldState,
snackbarHost = {
SnackbarHost(it) { snackbarData ->
Snackbar(
actionColor = I want a color here!
snackbarData = snackbarData
)
}
},
Using this set up, if 2 snackbars are triggered back to back, I can action both. You action the second, and then you can action the first. I like this functionality.
The only way I can get a colour in this way, is to set a global variable in the onClick but that is incredibly gross. Changing a local variable in the same file does not work.
Alternatively, I can trigger a recomposition via the ViewModel which will trigger showing a snackbar with the correct colour, but then I lose the functionality of triggering 2 items and still being capable of actioning both snackbars one after the other.
I even tried putting the colour into the action label so i could split it out, but I can't instantiate the existing SnackbarDataImpl to then recreate it without it because it's private. I would have to copy the entire scaffold implementation to simply add a colour this way as the host has to come from the scaffold
Is there some better way I can do this? It's way too complicated for something as simple as wanting to set a colour based on the action?
CodePudding user response:
Maybe you could use something like this:
var color by rememberSaveable { mutableStateOf(Color.Red) }
Snackbar(
actionColor = color,
...
)
CodePudding user response:
Probably your best bet is to have your ViewModel
store the snackbar color:
class MyViewModel : ViewModel() {
var snackBarColor by mutableStateOf(Color.Blue)
(...)
}
And in the Scaffold
:
Scaffold(
scaffoldState = scaffoldState,
snackbarHost = {
SnackbarHost(it) { snackbarData ->
Snackbar(
actionColor = myViewModel.snackBarColor,
snackbarData = snackbarData
)
}
},
So now when calling the Snackbar
, also set the snackBarColor
in the ViewModel
:
onClick {
myViewModel.snackBarColor = Color.Red
scope.launch {
val snackbarResult = scaffoldState.snackbarHostState.showSnackbar(
message = "message",
actionLabel = "action"
)
when (snackbarResult) {
SnackbarResult.ActionPerformed -> do something
SnackbarResult.Dismissed -> do something
}
}
}
As long you have the same instance of the MyViewModel
both in the Scaffold
and where you are calling the onClick
, the Scaffold
will observe the snackBarColor
from MyViewModel
and update automatically when it changes.