Navigating Nested DialogFragments in Android

This post explores how to create navigation between nested DialogFragments. “Why would you need to do this?” you may be wondering. I was attempting to navigate through multiple views within a dialog without layering DialogFragments on top of each other. The issue with simply layering the dialogs is clearest when displaying the dialog using an animation: You end up with multiple dialogs on top of each other, occupying the same elevation, which goes against material design concepts (and looks pretty unnatural). One solution is to use a ViewPager to navigate in between child fragments. This approach has the overhead of creating a ViewPager and corresponding adapter, then adding and removing pages with the adapter when necessary. Instead of using a ViewPager, I wanted to use only FragmentTransactions in order to minimize overhead. I also needed my implementation to adapt based on the device’s screen size, showing a full screen dialog on phones, and a normal sized dialog on tablets. I created this EmbeddedDialogFragment in order to solve a few key issues: displaying the correct title in the toolbar, handling back clicks correctly, and animating navigation.

Let’s break this down into the key issues that needed to be solved:

Making the correct transaction:

The above method is called in the child fragments to transition to another page. This method is only called when adding new views on to the view hierarchy. Adding the transactions to the backstack makes is easy to reverse this transition later on, when the user taps the back button. The R.id.fragment_content is simply a FrameLayout in the corresponding layout file shown below:

The layout file is only more complex than just the fragment_content layout in order to show a toolbar above the child fragment. Otherwise, a simple xml file with a FrameLayout as the only view would work.

Adding animation is really simple and definitely worth the one line of code you need to write:

transaction.setCustomAnimations(R.anim.slide_left_from_right, android.R.anim.fade_out, android.R.anim.fade_in,
R.anim.slide_out_right_from_left);

Making the back button work correctly took a bit of a workaround in terms of intercepting the user tap. I needed to access the dialog maintained in the fragment:

Displaying the correct title in the toolbar was the trickiest part of this solution. In the onBackPressed() method, I first popped the back stack in order to reverse the previous transaction with animation. Then I looked up the correct title for the fragment transaction on top of the stack. I needed to work around some wonkiness relating to the state of the back stack after a screen rotation, which is why I check if bdf is null even though I should have just retrieved it:

There is one issue that I couldn’t find a solution for: persisting pop animations through orientation change. My back stack remained intact after screen orientation, however the pop animations are not persisted by the OS. This appears to be a bug within Android and is noted in this post: