what is the correct way to do bottom tab navigatio...
# compose-android
a
what is the correct way to do bottom tab navigation. Ive seen : (1) one
NavHost
using restore state, singletop when navigating to tab: but cant restrict routes to a specific tab, but simpler to implement (2) somewhere read using multiple
navigation<>(..)
wrappers: downside is entering each navigation<> means have to hoop through the start destination (not a huge deal), but can put only certain routes in that navigation stack. Also seems that when i jump between the navigation graphs I cant preserve the backstack state and hit the tab starting route again (might be by design?) (3) chatgpt suggested multiple NavHosts for each tab with their own navigation controllers 😅 .
👀 1
s
Ignore chatgpt answer What is the hoop with navigation that you're concerned about? What do you mean by "can't preserve the backstack state and hit the tab starting route again"?
a
so you on Tab A Tab A -> Start (route A) -> Route B switch tab to Tab B switch tab back to A navigation state is reset back to Start rather than Route B, when each tab is its own
navigation<> { }
graph
s
Then you're doing the restoreState and saveState wrong. This should just work.
a
using
restoreState
and
singleTop
i think because they are different navigation graphs they immediately go back to start destination when navigating to them
a
rightt that examples uses (1) a single navhost for all tab navigation
s
Yup indeed, as you should. Hence I said ignore chatgpt answer, it's shit advice (as always)
a
Hahaha yeah. Makes sense . I’m writing a custom layer on top of compose navigation so I can tweak generated code to make the nested graphs virtual. Perfect 👌
s
https://github.com/raamcosta/compose-destinations Might wanna use this if you want things automatically done for you
a
built something similiar but more tailored to our companies practices. comes with more benefits including tailoring the code generation just the way we want
it uses jetpack compose navigation typesafety directly vs a layer on top of it. looked into that library, but decided against using it
s
Yeah we don't use it either, but I appreciate what it brings to the table. I can't pretend I know anything about your internal needs, but I'm still not 100% sure about what exactly you want to hide away. Is it on the navigation side, aka where you write where you want to navigate to, or on the dsl side, where you define how the graph itself is setup? I'm just curious is all 👀
c
yeah. basically never do multiple nav hosts. I think Ian said that theres like one case where that's a thing. any app that i jumped into that used multiple navHosts had SOOO many issues. the link Stylianos put is basically what i copy pasta into every project. Needs to be updated for material3 though. I think bottom nav can be done slightly differently now that shared element transitions are a thing. so if you wanted you could use SE transitions to help with a nav bar on each individual screen. I just always put it on the top level and call it a day. Has worked fine in like 10 prod apps ive done.
👍 1
a
How would you do different ui wrappers for each navigation flow? Is there any examples of reusing ui . It seems not great to recreate a persistent search bar or bottom navigation.
Ah I just read the bottom part. So you duplicate it in every screen?
Fwiw I managed to code in nested nav host. And have a router handle which route in which graph, using generated code that forces the knowledge of which graph a route is on, but def took a bit of work to get right
s
Shared elements let you just have a SharedBottomNav composable which you can conditionally have or not have on each destination that needs it. The shared element will make it look as if it's a top level thing instead. No code duplication needed if you just extract that in a separate composable, or even pass it down as a composable slot to the destinations that need it. re multiple NavHosts again: And you break support for the deep link handling in the process. You also break the built-in support for predictive back while you're at it. You also break what
navigateUp
does for you with recreating the right backstacks in the scenarios when that's needed. You also lose the ability to look up the hierarchy to find some destination you might be interested in if it happens to be on some other NavHost instead. Same with potentially grabbing the parameters from another destination in the backstack, which you can normally do on a NavHost. Still not a good idea, even if you "get it right" with a lot of effort. Especially when the alternative of just using one NavHost is so much simpler and already works 😅
a
Not sure a slot composableto every destination is scalable when it’s 400 screens 🤣 but that said, I think I understand what you mean. It’s also possible to code in this logic into the code generator. I think compose destinations has this ability too so it doesn’t seem too wild. Definitely will have to try it out, and it can remove that complex logic in the process..just surprised (could make a feature request ) that jetpack navigation has no built in way to do just this
These are all valid points! thank you color
s
If the bottom nav is present in all 400 screens you can keep it global 🤷
c
Yeah. FWIW, I don't use the shared element route. I do the single nav bar and it hides/shows (with an animation!) depending on the nav state single source of truth
a
Yeah not every screen uses it, like login sign up and other flows in the app, but yes I also have a shared one- it’s just nested inside the destination with a nested navhost under it. I’ll take a look at these examples! Thanks
i ended up reactively picking the wrapper UI based on which navigation graph is showing in a single nav host. works like a charm!
🦠 2