Join us on the livestream at Android Dev Summit on 7-8 November 2018, starting at 10AM PDT!

Update UI components with NavigationUI

The Navigation Architecture Component includes a NavigationUI class. This class contains static methods that manage navigation with the top app bar, the navigation drawer, and bottom navigation.

Listen for navigation events

Interacting with the NavController is the primary method for navigating between destinations. The NavController is responsible for replacing the contents of the NavHost with the new destination. In many cases, UI elements—such as a top app bar or other persistent navigation controls like a BottomNavigationBar—live outside of the NavHost and need to be updated as you navigate between destinations.

NavController offers an OnNavigatedListener interface that is called each time the NavController navigates to a new destination. A new listener can be registered via the addOnNavigatedListener() method, as demonstrated in the example below. Note that when calling addOnNavigatedListener(), if the current destination exists, it is immediately sent to your listener.

Kotlin

navController.addOnNavigatedListener { navController, destination ->
  textView.setText(destination.label)
}

Java

navController.addOnNavigatedListener(new NavController.OnNavigatedListener() {
  @Override
  public void onNavigated(@NonNull NavController navController,
          @NonNull NavDestination destination) {
    textView.setText(destination.getLabel());
  }
});

NavigationUI uses OnNavigatedListener to make these common UI components navigation-aware. Note, however, that you can also use OnNavigatedListener on its own to make any custom UI or business logic aware of navigation events.

Top app bar

The top app bar provides a consistent place along the top of your app for displaying information and actions from the current screen.

NavigationUI contains methods that automatically update content in your top app bar as users navigate through your app. For example, NavigationUI uses the destination labels from your navigation graph to keep the title of the top app bar up-to-date.

NavigationUI provides support the following top app bar types:

AppBarConfiguration

NavigationUI uses an AppBarConfiguration object to manage the behavior of the Navigation button in the upper-left corner of your app's display area. By default, the Navigation button is hidden when a user is at a top-level destination of a navigation graph and appears as an Up button in any other destination.

To use the start destination of your navigation graph as the only top-level destination, you can create an AppBarConfiguration object and pass in the corresponding navigation graph, as shown below:

val appBarConfiguration = AppBarConfiguration(navController.graph)

If you want to customize which destinations are considered top-level destinations, you can instead pass a set of destination IDs to the constructor, as shown below:

val appBarConfiguration = AppBarConfiguration(setOf(R.id.main, R.id.android))

Include a navigation drawer

To support a navigation drawer, you can also pass a DrawerLayout to the AppBarConfiguration constructor. When using a DrawerLayout, the drawer icon is displayed on all top level destinations.

Kotlin

val appBarConfiguration = AppBarConfiguration(navController.graph, drawerLayout)

Java

AppBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph())
    .setDrawerLayout(drawerLayout)
    .build();

Create a Toolbar

To create a Toolbar with navigation support, first define the bar in your main activity, as shown below:

<LinearLayout>
    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar" />
    <fragment
        android:id="@+id/nav_host_fragment"
        ... />
    ...
</LinearLayout>

Next, call setupWithNavController() from your main activity's onCreate() method, as shown below:

override fun onCreate(savedInstanceState: Bundle?) {
    setContentView(R.layout.activity_main)

    ...

    val navController = findNavController(R.id.nav_host_fragment)
    val appBarConfiguration = AppBarConfiguration(navController.graph)
    findViewById<Toolbar>(R.id.toolbar)
        .setupWithNavController(navController, appBarConfiguration)
}

Include CollapsingToolbarLayout

To include a CollapsingToolbarLayout with your Toolbar, first define the Toolbar and surrounding layout in your main activity, as shown below:

<LinearLayout>
    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/tall_toolbar_height">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleGravity="top"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"/>
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>

    <fragment
        android:id="@+id/nav_host_fragment"
        ... />
    ...
</LinearLayout>

Next, call setupWithNavController() from your main activity's onCreate method, as shown below:

override fun onCreate(savedInstanceState: Bundle?) {
    setContentView(R.layout.activity_main)

    ...

    val layout = findViewById<CollapsingToolbarLayout>(R.id.collapsing_toolbar_layout)
    val toolbar = findViewById<Toolbar>(R.id.toolbar)
    val navController = findNavController(R.id.nav_host_fragment)
    val appBarConfiguration = AppBarConfiguration(navController.graph)
    layout.setupWithNavController(toolbar, navController, appBarConfiguration)
}

Action bar

To include navigation support with the default action bar, call setupActionBarWithNavController() from your main activity's onCreate() method, as shown below. Note that you need to declare your AppBarConfiguration outside of onCreate(), since you also use it when overriding onSupportNavigateUp():

private lateinit var appBarConfiguration: AppBarConfiguration

...

override fun onCreate(savedInstanceState: Bundle?) {
    ...

    val navController = findNavController(R.id.nav_host_fragment)
    appBarConfiguration = AppBarConfiguration(navController.graph)
    setupActionBarWithNavController(navController, appBarConfiguration)
}

Next, override onSupportNavigateUp() to handle Up navigation:

override fun onSupportNavigateUp(): Boolean {
    return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}

Tie destinations to menu items

NavigationUI also provides helpers for tying destinations to menu-driven UI components. NavigationUI contains a helper method, onNavDestinationSelected(), which takes a MenuItem along with the NavController that hosts the associated destination. If the id of the MenuItem matches the id of the destination, the NavController can then navigate to that destination.

As an example, the XML snippets below define a menu item and a destination with a common id, details_page_fragment:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    ... >

    ...

    <fragment android:id="@+id/details_page_fragment"
         android:label="@string/details"
         android:name="com.example.android.myapp.DetailsFragment" />
</navigation>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    ...

    <item
        android:id="@id/details_page_fragment"
        android:icon="@drawable/ic_details"
        android:title="@string/details" />
</menu>

If your menu was added via the Activity's onCreateOptionsMenu(), for example, you can associate the menu items with destinations by overriding the Activity's onOptionsItemSelected() to call onNavDestinationSelected(), as shown below:

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    val navController = findNavController(R.id.nav_host)
    return item.onNavDestinationSelected(navController) || super.onOptionsItemSelected(item)
}

Now, when a user clicks the details_page_fragment menu item, the app automatically navigates to the corresponding destination with the same id.

Bottom navigation

NavigationUI can also handle bottom navigation. When a user selects a menu item, the NavController calls onNavDestinationSelected() and automatically updates the selected item in the bottom navigation bar.

To create a bottom navigation bar in your app, first define the bar in your main activity, as shown below:

<LinearLayout>
    ...
    <fragment
        android:id="@+id/nav_host_fragment"
        ... />
    <android.support.design.widget.BottomNavigationView
        android:id="@+id/bottom_nav"
        app:menu="@menu/menu_bottom_nav" />
</LinearLayout>

Next, in your main activity class, call setupWithNavController() from your main activity's onCreate() method, as shown below:

override fun onCreate(savedInstanceState: Bundle?) {
    setContentView(R.layout.activity_main)

    ...

    val navController = findNavController(R.id.nav_host_fragment)
    findViewById<BottomNavigationView>(R.id.bottom_nav)
        .setupWithNavController(navController)
}