Hello everyone. Does anyone know how to solve this...
# compose
v
Hello everyone. Does anyone know how to solve this problem: I have a shared
BottomBar
, but each
Screen
needs its own
TopBar
. I tried doing this using
LocalCompositionProvider
, but it created a race condition: the closed
Screen
rendered the
TopBar
after the open
Screen
.
e
How are you sharing the
bottomBar
? This is 99% of the apps I build, there's a screen that hosts the
bottomBar
and handles navigation between tabs. Each screen has their own
scaffold
and their own
topBar
.
v
@Ernestas, If you look at the Play Market, for example, the
BottomBar
is shared across all sections, but all other content, including the
TopBar
, dynamically switches depending on the selected tab. I considered creating a nested
Scaffold
, but as far as I know, it could cause a performance hit.
e
I understand that, my apps are built the same way. I mean how are you trying to share the
bottomBar
currently? I have a
DashboardScreen
that hosts the bottomBar, and then each screen (eg.:
MenuScreen
) has their own topBar.
Copy code
@Composable
private fun DashboardScreen(
    navController: NavHostController,
    <...>
) {
    Column(modifier = modifier) {
        BottomNavigationHost(navController = navController)
        BottomNavigationBar(
            items = viewData.items,
            selectedItem = viewData.selectedItem,
            onClick = { onAction(DashboardAction.SelectBottomNavigationItem(it)) },
        )
    }
}

@Composable
private fun MenuScreen(
    <...>
) {
    Scaffold(
        topBar = { ... }
    )
}
jetpack compose 1
v
@Ernestas In that case, how do you draw the bottom panel? Do you use a regular
Column
?
e
If by bottom panel you mean the bottom navigation bar, then I simply use the material component for that
v
@Ernestas No, I mean how do you position it? Shouldn't the
BottomBar
be positioned inside the
Scaffold
for it to be positioned correctly? I currently have a
HostScren
like this.
Copy code
@Composable
fun HostScreen(
    modifier: Modifier = Modifier
) {
    Scaffold(
        bottomBar = {
            SharedBottomBar(
                // params
            )
        }
    ) {
        NavHost(
            // params
        )
     }
}
e
I see, I'm sure you can do that, I don't remember the reason why I went with a simple column. I use weight modifier to make the navhost fill all available height
Copy code
Column(modifier = modifier) {
        BottomNavigationHost(
            <...>
            modifier =
                Modifier
                    .weight(1f)
                    .consumeWindowInsets(WindowInsets.navigationBars),
        )
        BottomNavigationBar(...)
}
kodee loving 1
r
I recommend @Tunji Dahunsi’s approach: https://www.tunjid.com/articles/ui-layer-architecture-for-persistent-ui-elements-68248e8ecc8e85f53ce1aa46. TL;DR: Use SharedTransitionScope to create a persistent scaffold for each screen. Root level ui elements (bottom bar examples above) are inflexible and tightly coupled to your root composable. You don't need root level ui elements anymore with Compose. P.S. TJ is one of the author's of the Android architecture recommendations and used to work at Google.
🙌 1
kodee loving 1
🫶🏾 1
v
@Ryan Payne , Thank you very much, this looks like what I was trying to understand and do. blob heart
r
Happy to help 🙂