The demo-app shows the usage of the new Navigation Architecture Component in colaboration with the Bottom Navigation bar.
The bottom navigation was introduced 2 years ago as a material design pattern. The goal was to give the user quick access to 3-5 top-level destinations in an Android app, but an appropriate implementation was missing for long time. Meanwhile Goole introduced the Bottom Navigation bar as an implementation.
The common architectural approach for such a top level navigation would be to make use of Fragments which are added/replaced in a FrameLayout
serving as a holder in the Activity's view hierarchy. The FragmentManager
used for dealing with fragments within an Activity only knows one backstack. Building up a backstack for each single view section accessible by the Bottom Navigation bar was impossible. Therefore the "old" pattern behavior was about to remove the whole backstack when the user switched from one section to another.
But this wasn't the best user experience. Other approaches popped up, like the Conductor framework making it possible to maintain different controller-based backstacks attached to different Router's used in one Activity.
The "new" pattern behavior is about to maintain the view state a user left in one section when navigating back to it.
With the new Navigation Architecture Component Google introduces a similar concept which uses a NavHostFragment
hosting a NavController
operating on a navigation graph.
<fragment
android:id="@+id/section_home"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph"
/>
Placing this xml snippet into your Activity gives you access to it's NavController
managing the navigation within the NavHost
. Based on the navigation graph it allows to navigate to another fragment defined as an action
or to pop the backstack.
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:startDestination="@id/homeFragment"
>
<fragment
android:id="@+id/homeFragment"
android:name="com.dirkeisold.navigation.usecase.home.HomeFragment"
android:label="HomeFragment">
<action
android:id="@+id/action_homeFragment_to_homeDetailFragment"
app:destination="@id/homeDetailFragment"
/>
</fragment>
<fragment
android:id="@+id/homeDetailFragment"
android:name="com.dirkeisold.navigation.usecase.detail.DetailFragment"
android:label="HomeDetailFragment">
</fragment>
</navigation>
To maintain a fragment backstack for each view section of the Bottom Navigation bar a possible solution would be to use several NavHostFragments
:
<FrameLayout
android:id="@+id/section_home_wrapper"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/navigation"
app:layout_constraintTop_toTopOf="parent"
>
<fragment
android:id="@+id/section_home"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="false"
app:navGraph="@navigation/nav_graph_section_home"
/>
</FrameLayout>
<FrameLayout
android:id="@+id/section_dashboard_wrapper"
android:layout_width="match_parent"
android:layout_height="0dp"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="@id/navigation"
app:layout_constraintTop_toTopOf="parent">
<fragment
android:id="@+id/section_dashboard"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="false"
app:navGraph="@navigation/nav_graph_section_dashboard"
/>
</FrameLayout>
<FrameLayout
android:id="@+id/section_notification_wrapper"
android:layout_width="match_parent"
android:layout_height="0dp"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="@id/navigation"
app:layout_constraintTop_toTopOf="parent">
<fragment
android:id="@+id/section_notification"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="false"
app:navGraph="@navigation/nav_graph_section_notifications"
/>
</FrameLayout>
Each navigation host (NavHostFragment) contains its own NavController
based on a specific Navigation Graph and maintains its own Fragment backstack. Initially only the first FrameLayout
containing the home section will be visible to the user. When switching view sections the appropriate FrameLayout
will be shown to the user, the others hidden. The view state of each view section backed by a NavHostFragment
and its NavController
will be maintained and not changed.
The Android Studio 3.2 provides a nice graphical editor for designing a Navigation Graph.
Finally, Google comes up with a useful architecture component for implementing a Navigation Graph programmatically and visually, too.