Responsive Dialogs with Custom Navigator

Safa Orhan
ProAndroidDev
Published in
4 min readOct 17, 2020

--

This blog post is intended to be a part of the write-up series: Modern Android Apps with Jetpack Navigation which was originally a talk given by Safa Orhan (it’s me) and Taso Dane (an awesome guy) in .droidcon EMEA 2020 conference.

Last year, when we were working for Wayfair DE we worked on an app where we were lucky enough to architect a new app from scratch. We tried bunch of new libraries and frameworks including the Jetpack Navigation.

The app was a tablet-first app but we were also fully supporting phone layouts. When the product team introduced dialogs to the UI they wanted dialogs to show as a modal on tablets and full screen on phones.

An example fragment shown “in full screen on phones” vs “in a modal on tablets”

The dialogs were more than to show some simple messages, they were login dialogs and other functional parts so we decided to use Fragments.

Since we were using Fragments, the dialogs became a natural part of our Navigation mechanism.

We wanted to handle this new custom logic of showing dialogs in custom layouts on tablets and on phones without explicitly including this logic to all places we show a dialog.

We also wanted to make this feature of showing dialogs a first class citizen of our navigation architecture.

The end result was satisfying to our eyes:

navigation_graph.xml

When we wanted to display a Fragment in a modal, we were going ahead to our navigation graph and changing the <fragment tag into <modal-fragment tag.

Converting a fragment into a modal fragment was that simple.

When we wanted to show this Fragment, we were just navigating to it!

Now let me show you how we built such a system.

The first step is building a custom navigator.

ModalFragmentNavigator.kt

In Jetpack Navigation library each destination tag like an <activity> tag or a <fragment> tag declared by a Navigator. So when the Navigation library is instructed to navigate into a specific destination, it finds the corresponding navigator searching by the tag.

To introduce a new tag, we created a new navigator: ModalFragmentNavigator. Whenever we navigate to a <modal-fragment> marked destination, Navigation library will give our navigator full control to do the job.

We cheated a little bit and studied how the FragmentNavigator inside the library works and built a similar Navigator with some modifications.

The modifications were to add some business logic, like showing fragments with different settings on phones and tablets, and ensuring there is only one modal fragment in the fragment back stack at a time.

ModalFragmentNavigator.kt

In the highlighted part you can see that we inflate a ModalFragment and sending the class name of the original fragment as an argument.

The second step is to add the new navigator into the NavController

To add the navigator you need to use navigatorProvider.addNavigator(…) method where you set up your navigation library.

MainActivity.kt

Something to note here is that you need to inflate your navigation graph manually instead of using XML so that everything works without a hiccup.

That is how we built the custom navigator added it into the NavController

Also, let me show you how we dealt with showing the Fragment in different forms on phones and tablets.

As you remember, in the ModalFragmentNavigator we were navigating into a fragment called ModalFragment, now let’s see what is it.

The Modal fragment is actually an invisible wrapper and it inflates the given Fragment inside as a child fragment. And the layout of the container that it inflates the child fragment is different on tablets and phones.

ModalFragment.kt

This was how we built an extension that provides a custom behavior into our navigation architecture.

It was fun and robust and encapsulated well so that it’s not visible to the rest of the codebase.

More from the talk will come. Stay tuned!

Thanks a lot for reading, don’t forget to clap 👏 and share this article if you like what you read!

Want to keep in touch? Follow me on Twitter 🐦

--

--