im having an issue trying to animate my details pa...
# compose
j
im having an issue trying to animate my details page using navhost with a bottom naveigation bar... I used enter/exit transitions of slide into/ slide out of on both the navcontroller and the bottom bar, but the details view only has the height of the previous view initially and then snaps to full height after the transition ends which is kind of jank.
I guess the main issue is resizing of the rest of the view when i animate dismiss my bottom nav.
a
I have tried so many things to try to avoid this but i simply could not find a smooth way of doing it with using just 1 wrapper scaffold and 1 navhost to wrap all of the nested graphs / destinations
the only way i know is to have 2 navhosts
one that is separate to the bottom bar destinations
and the other one for the rest of the app flows
In an app where there is a lot of this it causes so much jank and lag
My solution looks like this
Copy code
@Serializable
object DashboardRoute

@Serializable
private object Dashboard

fun NavController.navigateToDashboard(navOptions: NavOptions? = null) {
    this.navigate(route = DashboardRoute, navOptions = navOptions)
}


fun NavGraphBuilder.dashboard(
    builder: NavGraphBuilder.(NavController) -> Unit
) {
    navigation<DashboardRoute>(startDestination = Dashboard) {
        composable<Dashboard> {
            val navController = rememberNavController()
            val navBackStackEntry by navController.currentBackStackEntryAsState()
            val currentDestination = navBackStackEntry?.destination
            LaunchedEffect(currentDestination) {
                val routes = navController.currentBackStack.value.joinToString(" >>> ") {
                    it.destination.route.toString()
                }
                println("Dashboard BackStack: $routes")
            }
            Scaffold(
                contentWindowInsets = WindowInsets(0, 0, 0, 0),
                bottomBar = {
                    NavigationBar(
                        navController = navController,
                        currentDestination = currentDestination
                    )
                }
            ) { contentPadding ->
                Box(
                    modifier = Modifier
                        .fillMaxSize()
                        .padding(contentPadding)
                        .consumeWindowInsets(contentPadding)
                ) {
                    NavHost(
                        navController = navController,
                        startDestination = RelativesScreen,
                        modifier = Modifier.fillMaxSize(),
                        builder = { builder(navController) }
                    )
                }
            }
        }
    }
}
and it looks like this
d
Do you need the scaffold? Can you use a Box instead, put bottom alignment on the BottomBar composable and pad your screen content with the height of the bottom bar for the screens that show a bottom bar. That's what I have and it works fine without the "jump" that a Scaffold or a Column introduces
a
Tried, you still end up calculating the size difference so this doesn't work either
d
Not really if you do what Material3 does and your BottomBar has a fixed height
a
I would be happy to see some code, I tried setting a fixed height padding and that as i said doesn't do the job either
d
Can't quite share real code as it's not public but a toned down version is as simple as this
Copy code
Box(
    modifier = Modifier.fillMaxSize()
) {
    NavHost()
    Box(
        modifier = Modifier.align(Alignment.BottomCenter)
    ) {
        AnimatedVisibility(
            visible = showBottomNav,
            modifier = Modifier,
            enter = bottomNavEnter,
            exit = bottomNavExit,
        ) {
            BottomBar()
        }
    }
}
Then each Composable route inside the NavHost can add bottom padding to it's elements, with correct first frame because you know which screen has the bottom nav showing and which doesn't
a
I tried this, and it seems to work nicely 🙌 Guess I was too lenient on the scaffold wrapping the whole app
Thanks for the take
The drawback is that you have to add manual padding to the elements as you said.
d
Yeah I suspect it's possible to overcome that if you copy Scaffold's code and change it so it lays out elements as if they are in a Box instead of a Column but also keep the part where it measures the bottom nav and exposes its size as contentPadding. Then you'd get the best of both worlds but you're back to Subcomposition
Another option is to use Shared element ransitions and move your BottomBar to your screen content
a
No you could use scaffold I was just too lenient on the bottom bar slot I guess
d
The latter is probably much easier and neater code tbh
a
this seems to work perfectly fine
best of both worlds
only problem is need to add spacers
d
But then you're not using any functionality of Scaffold if you have it like that really so you're just paying the cost of subcomposition for no reason
a
i get free paddings
d
Padding of what? contentPadding I bet is now always 0
a
Unless i it is being consumed it is not always zero
the content itself is within the navhost so it is being applied no?>
d
The actual padding values inside the contentPadding variable will be 0,0,0,0 Print them out and you'll see. I'm 99% sure your Scaffold now gives you no benefit/functionality that can't be achieved without Subcomposition. But you're still paying the price of it by using it over Box/Column/Whatever
a
I can test 🙂
Good input
Paddings are PaddingValues(start=0.0.dp, top=0.0.dp, end=0.0.dp, bottom=0.0.dp)
Youre right again, i guess i can just fallback to putting a background modifier on the top parent box
Thanks for the input this was very helpful
j
awesome! will try to implement this week. Thanks !!