Is there a way to share a “header” composable in ...
# compose
n
Is there a way to share a “header” composable in a nested graph without creating separate navControllers? The only way I can see is to have a composable() with a header and then a new NavHost(). But afaik having multiple NavHosts is not recommended.
d
This is a similar problem to what I have run into a couple times and wondered the same myself - although for a Bottom Nav instead of a header. Sharing my understanding here, with the hope that we can find a solution together or somebody to help us both: Say your app has 3 screens - two that should be showing a shared bottom nav bar (or header) and one that shouldn't display it (e.g. screen is part of some flow that shouldn't be showing the bottom nav/header). One could model their app like
Copy code
Scaffold(
bottomBar = if (navController.currentDestination.showBottomBar) {....}

...
) {
// NavHost here etc
}
Now what this means is that the NavHost will have a different height on the screens that have a bottom bar vs the ones that don't. Which itself suggests to me that when you try to navigate from the screen that has a bottom nav to the one that doesn't, the navigation animation is started (think e.g. slideInFromRight) the screen will resize which makes it "jump" and I hate it.
Now depending on when exactly you try to hide the BottomBar, it will look slightly better or worse but I haven't found a solution that looks aesthetically pleasing unless I do use 2 NavHosts (which is then annoying as you need to keep track of which one should be used etc). @nlindberg is that similar to the issues you're running into? How have other people solved this? Is there any sort of guidelines from Googlers on this that we can lean on?
n
I think my issue is a bit different. Mine is more that Screen 4 has a nested graph with 5 routes 4.1, 4.2, 4.3 etc. Between these routes I would like to show a header with title e.g. Screen 4.2. I dont want to define the Header for the nested graph all the way outside the root graph and hide it for any root routes that isnt 4. Regarding your issue with Bottom navigation, I think its fine to have it defined outside the NavGraph and have it be hiden shown depending on what routes you want to have it in. I have a working soluton for this. But I’m not using Scaffold or the bottom navs from material. I wrote in response here to another guy some time ago, ill find the post sec.
d
I see but if I am reading that right this has the limitation that you can't use the paddingvalues provided then? Which is quite a problem For your problem - depending on the exact transition you want I think you have a few options - Could create a composable ScreenWithHeader (need a better name) that takes a content composable param and places it with a header? Not sure if you have much choice here if you wanna avoid nested NavHost
n
The problem with that is that the header gets animated as well then. Yeah don't have padding values in my solution to the bottom nav bar.
d
Yeah it will get animated but I can't think of a way (or rather, one that is not nasty) to not animate it without a nested nav host. Not having padding values is perhaps is more down to the fact you don't need a Scaffold in your app but if you use SnackBar and Fab I think you won't have a choice soo not sure if that solution will work for me/other ppl
i
Here's the last conversation about this and how what you're really looking for is shared elements (i.e., elements that are shared between a subset of screens): https://kotlinlang.slack.com/archives/CJLTWPH7S/p1657125808017769
n
Thanks @Ian Lake, as I understand it, it's something that is in the pipeline, unless I "hoist" the header all the way outside the root NavHost? It is a bit "feelswierd" to have the header for a specific nested graph be added all the way out in the root of the app 🥲 so looking forward to the shared elements stuff 🙌
i
Yep, you have the same issue with just a normal
AnimatedContent
- it has to either be within the
AnimatedContent
(and therefore the transitions you apply to everything in the screen) or it has to be lifted outside the
AnimatedContent
if it actually needs to stay where it is as the content changes
s
I am so excited about this being possible now, so I will absolutely reply on a 2 year old thread 😅 Now that this https://github.com/androidx/androidx/commit/c5f36c050e6ec86e8a504031b3cd7602a11f4d9e is merged and available in the latest androidx snapshot releases, along with the latest snapshot navigation release, you can get exactly this working by markging the top app bar with a
.sharedElement
modfier and simply adding the same key in
rememberSharedContentState
. This is a video of this in action https://x.com/GakisStylianos/status/1776910738616959118.
🎉 1
l
I took it for a spin and it did absolutely deliver on what I was hoping for. In our app we have a
SharedToolbar
composable that did magic to instantiate only 1 toolbar and use this across the various screens. This worked, but it was always supposed to be a stop-gap solution until something like
.sharedElement
was in place. So my quick attempt simply re-did some of the
SharedToolbar
and I had to leverage context receivers to ease my migration burden. Which mostly involved slapping it on every navgraph builder. But after compiling, fixing all minor compile errors — it just worked. A shared toolbar that stays in place; but animates left-right when it first becomes visible, but simply changes on subsequent screens. Well that was easy. Sure we’ll clean this up in the future. Likely we’ll unroll the
SharedToolbar
composable to give more control. But wow, amazing work! Thanks @Doris Liu and everyone involved! Keep it up!
🦜 1
🎉 2
s
it just worked
Hell yeah. I had the exact same reaction to this 😅
❤️ 1
d
So glad to hear the SharedToolBar woking well out of the box. @Lasse Magnussen And thank you @Stylianos Gakis for the shoutout. BTW, if at some point your toolbar needs to change color or content in different screens, consider giving
sharedBounds
a try. 😉
❤️ 3
👍 1
a
Hi, @Stylianos Gakis, Just wondering is the same concept could be applied to BottomNavigation? In my head, wouldn't the Bottom Navigation animation (Animation of the unselected item and the selected item) be a problem in those case?
s
It might be a problem, depending on what kind of animation you want to happen I suppose. Have you tried doing this and found it looking odd?
a
Not yet but I'm interested with the idea. I'd try it once I get the chance. Just wondering if you had experience something like this.