Illustration by Ana Teresa Silva from the lovely We Are Systematic. Thank youuuuuu❤️✨

Introducing Navigation-Material 🧭🎨️

Navigation-Compose (well, kinda) has an exciting new feature: Support for bottom sheet destinations!

Over the past (almost) 6 months, I worked on a library in collaboration with the Navigation team that offers support for Modal Bottom Sheets in Navigation Compose. Navigation with Fragments has long supported DialogFragments, and with today’s release of the Navigation Material library, we are providing the same feature for composable bottom sheets with Navigation Compose. Since modal bottom sheets are still an experimental Compose-Material API, the library will be released as part of Accompanist, a collection of extension libraries for Jetpack Compose.

All AndroidX libraries, Navigation and Compose included, follow strict semantic versioning as explained on the AndroidX releases page. This means that any API that isn’t experimental is set in stone once a library goes to its Release Candidate (RC) phase. It would take a major version bump (i.e., a ‘2.0’) to make breaking API changes to these stable APIs.

- Ian Lake about the versioning system of AndroidX libraries

Because of the versioning requirements for AndroidX libraries, Navigation Material will be offered as part of Accompanist, just like navigation-animation. Think of it as an incubator until the bottom sheet APIs are fully grown up! Enough of the talking — let’s look at how you can use it!

Getting started!

Navigation Material is fresh out of the oven, built off today’s release of Navigation 2.4.0-alpha06! There are a few easy steps to get started:

  • Create a BottomSheetNavigator using the rememberBottomSheetNavigator() function
  • Add the BottomSheetNavigator to your NavController
  • Wrap your existing NavHost in the ModalBottomSheetLayout composable provided by Navigation Material. If you don’t have a NavHost yet, we’ll create one!
  • Now you’re ready to define bottom sheet destinations using the new bottomSheet function!

Let’s go through it! First, we’ll add a dependency on the Navigation Material library:

This enables you to access APIs like BottomSheetNavigator. BottomSheetNavigator is a Navigator handling composable bottom sheet destinations. To make the navigation library aware of it, we register it with the NavController:

Now, we wrap our existing NavHost composable in the ModalBottomSheetLayout composable provided by the Navigation Material library. If you don’t have a NavHost yet, you can add it here.

The ModalBottomSheetLayout composable is a helper to create a Material ModalBottomSheetLayout from a BottomSheetNavigator.

Note: We register the navigator with the NavController directly in the composition, not in an effect like SideEffect. This is because the NavHost needs this information when trying to build the navigation graph which will include a bottom sheet destination in just a bit! We recently landed some changes in Navigation Compose that makes this safe.

Back to the role of our navigator: BottomSheetNavigator exposes the current destination’s sheet content, or nothing if there currently is no active bottom sheet destination. This composable is then set as the ModalBottomSheetLayout‘s sheetContent.
Essentially, a BottomSheetNavigator drives a ModalBottomSheetState, showing and hiding the sheet appropriately and coordinating the sheet’s content.

Finally, we can define a bottom sheet destination using the new bottomSheet extension function on NavGraphBuilderprovided by Navigation Material. The bottomSheet function takes a composable lambda with a NavBackStackEntry parameter. That means that you will have access to the bottom sheet’s back stack entry which you can use to look at arguments and more.

And that’s it! Bottom sheet destinations are regular navigation destinations, with the difference that they are floating window destinations. This means that they overlay other destinations on the back stack, just like dialog destinations do.

Navigating

You can navigate to bottom sheets just like any other destination:

You can navigate away from bottom sheet destinations as usual, or the user can dismiss the sheet by tapping on the scrim or tapping the back button. In this case, the sheet back stack entry will be popped off the back stack.

Navigating with Arguments

Bottom sheet destinations support the features of other types of destinations (like the composable destination type), like passing arguments:

That’s it! This library and its APIs are experimental and subject to change until the Material Bottom Sheet APIs are finalized. We would love to hear your feedback over in the Accompanist repository!

The Navigation team also released the new Navigation Animation library today, bringing support for animations with Navigation Compose. Check out their post!

Why do we need this library?

Bottom Sheets in Jetpack Compose

Coming from the world of Activities, Views and Fragments, getting used to how Bottom Sheets are handled in Compose can be a bit of a learning curve. In Compose, state is passed down and events are passed up. Implementing bottom sheets means that a layout has to host both the sheet’s content and the layout’s body that the sheet is shown on top of:

In bigger apps, bottom sheet content needs to be able to change: Either because it needs to be composed based on arguments or there might be different sheets that should be shown depending on the application’s current screen. The body of the Material ModalBottomSheetLayout is responsible for hosting the different destinations. To combine a Material ModalBottomSheetLayout with Jetpack Compose Navigation, the ModalBottomSheetLayout needs to host a NavHost:

A basic integration could look like this:

This integration will scale quite badly — all Composable destinations that need to show a bottom sheet need to be able to set the sheet content and maybe even access the ModalBottomSheetState. Back click and back stack handling are other issues not even considered in this example.
The code isn’t very straightforward to understand and can feel a bit counter-intuitive if you haven’t worked with bottom sheets in Compose before, especially in combination with Navigation.

To make our lives easier, we need a bridge that helps the NavHost and the NavController talk to the ModalBottomSheetLayout to coordinate the sheet’s sheetContent and the sheet’s visibility. Luckily, that’s what Navigation Material provides so that you don’t need to write all of this boilerplate code!

Get started using it today by heading over to the Accompanist documentation or jumping back to the above “Getting Started” section!

Thank you’s

Getting this library ready was a huge effort I spent several months on and I could not have done it without the support from some awesome folks. Thank you to Ian Lake for lots of patience, reviews, accepting contributions that made this library possible, suggestions and sharing your knowledge. Thanks to Matvey Malkov for helping me figure out some tricky bottom sheet things :) Thanks to Jeremy Woods for the collaboration between Navigation Animation and Navigation Material. Thanks to Chris Banes for maintaining Accompanist, it is truly awesome! Thank you to Mark Dickson, Hugo Visser, Andrew Kelly and Ben Weiss for reviewing this post! And finally, thank you to Yasmine Evjen for helping to find the emoji combo for Navigation Animation and Navigation Material.

If you want to hear more about this library’s story and technical details, follow this blog to get notified about the next story!

Android GDE & Android @snappmobile_io, working remotely from Hamburg, Germany. I like Kotlin, Animations and Rabbits! speakerdeck.com/jossiwolf