What's the best way to show a Snackbar on a multi-module, single activity, Compose only project?
This is how the project dependency graph looks like:
The only activity of the project is inside the app
module and it just sets the NavHost
as content .
Each feature
module provides a list of composable screens that will be shown on the NavHost
.
Each screen has its own Scaffold
, so it can easily show Snackbars from the each screen's ViewModel
.
There is a special feature
module, feature-debug
, that shows on a single screen, a list of composable provided by each feature
module , that are called debug sections. It is used to allow any feature
module to show automatically some settings inside the debug screen.
Each debug section has its own ViewModel
so it works exactly like a Screen. But it's missing a Scaffold, since it only takes a portion of the screen:
+-------------------------+
| Debug screen |
|-------------------------+
| |
| Feature A debug section |
| |
|------------------------ +
| |
| Feature B debug section |
| |
|------------------------ +
| |
| Feature C debug section |
| |
|------------------------ +
| |
| Feature D debug section |
| |
+------------------------ +
So I'm not sure how can I show a Snackbar on the Scaffold of the feature-debug
screen, from a composable that is declared inside another feature
module that has no visibility of the any class inside feature-debug
.
CompositionLocal
can be used to pass data through the composition tree implicitly.
The first thing to do is to declare a variable that must be visible by provider and consumers (in my case, I created it inside the core-ui
module):
val LocalSnackbarHostState = compositionLocalOf<SnackbarHostState> { error("No SnackbarHostState provided") }
Then the provider should wrap its children with a CompositionLocalProvider
:
val scaffoldState = rememberScaffoldState()
CompositionLocalProvider(
LocalSnackbarHostState provides scaffoldState.snackbarHostState
) {
Scaffold(
[...]
And finally the children can grab an instance of the SnackbarHostState
accessing the variable LocalSnackbarHostState
:
val snackbarHostState = LocalSnackbarHostState.current
I would only use a single snackbar for your entire app. It needs to be included at the root level of your UI hierarchy and accessible through a global object. This can be done by using a class that inherits from Application and placing a method inside that class to handle displaying the snackbar.
There's an example app showing how this is done. The demo app can be downloaded at:
https://github.com/JohannBlake/Jetmagic
When you run the app, open up the navigation tray and select any navigation item. On the screen that appears, click on the button labeled Return value from another screen
. This will take you to another screen where you select an item and return to the previous screen. The selected item will be shown in a snackbar. This snackbar is global throughout the app.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.