Connect UI Components To NavController Using NavigationUI - Android Developers
Connect UI Components To NavController Using NavigationUI - Android Developers
NavController using
NavigationUI
The Navigation component includes a NavigationUI
(/reference/androidx/navigation/ui/NavigationUI) class. This class contains static methods that
manage navigation with the top app bar, the navigation drawer, and bottom navigation.
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.
android:label="Page title"
When using NavigationUI with the top app bar implementations discussed below, the
label you attach to destinations can be automatically populated from the arguments
provided to the destination by using the format of {argName} in your label.
NavigationUI provides support for the following top app bar types:
Toolbar (/reference/android/widget/Toolbar)
CollapsingToolbarLayout
(/reference/com/google/android/material/appbar/CollapsingToolbarLayout)
ActionBar (/reference/androidx/appcompat/app/ActionBar)
For more information on app bars, see Set up the app bar (/training/appbar/setting-up).
Caution: If you pass a Toolbar as the argument to setSupportActionBar(), the ActionBar assumes
complete ownership of that Toolbar and you must not use any Toolbar APIs after that call. You can
use the support for the ActionBar (#action_bar) to connect the ActionBar to NavController.
AppBarConfiguration
NavigationUI uses an AppBarConfiguration
(/reference/androidx/navigation/ui/AppBarConfiguration) object to manage the behavior of the
Navigation button in the upper-left corner of your app's display area. The Navigation
button’s behavior changes depending on whether the user is at a top-level destination.
When the user is at a top-level destination, the Navigation button becomes a drawer icon
. To configure the Navigation button using only the start destination as the top-level
destination, create an AppBarConfiguration object, and pass in the corresponding
navigation graph, as shown below:
Kotlin (#kotlin)Java
AppBarConfiguration appBarConfiguration =
new AppBarConfiguration.Builder(navController.getGraph()).build(
In some cases, you might need to define multiple top-level destinations instead of using
the default start destination. Using a BottomNavigationView is a common use case for
this, where you may have sibling screens that are not hierarchically related to each other
and may each have their own set of related destinations. For cases like these, you can
instead pass a set of destination IDs to the constructor, as shown below:
Kotlin (#kotlin)Java
(#java)
AppBarConfiguration appBarConfiguration =
new AppBarConfiguration.Builder(R.id.main, R.id.profile).build()
Create a Toolbar
To create a Toolbar with NavigationUI , first define the bar in your main activity, as
shown:
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar" />
Note: When using a Toolbar, Navigation automatically handles click events for the Navigation button,
so you do not need to override onSupportNavigateUp()
(/reference/androidx/appcompat/app/AppCompatActivity#onSupportNavigateUp()).
To configure the Navigation button to appear as an Up button for all destinations, pass an
empty set of destination IDs for your top-level destinations when building your
AppBarConfiguration . This can be useful if, for example, you have a second activity that
should display an Up button in the Toolbar on all destinations. This allows the user to
navigate back to the parent activity when there are no other destinations on the back
stack. You can use setFallbackOnNavigateUpListener()
(/reference/androidx/navigation/ui/AppBarConfiguration.Builder#setFallbackOnNavigateUpListener(a
ndroidx.navigation.ui.AppBarConfiguration.OnNavigateUpListener))
to control the fallback behavior for when navigateUp() would otherwise do nothing, as
shown in the following example:
Kotlin (#kotlin)Java
(#java)
@Override
protected void onCreate(Bundle savedInstanceState) {
...
Include CollapsingToolbarLayout
To include a CollapsingToolbarLayout with your Toolbar, first define the Toolbar and
surrounding layout in your activity, as shown below:
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="@dimen/tall_toolbar_height">
<com.google.android.material.appbar.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">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
Next, call setupWithNavController()
(/reference/androidx/navigation/ui/NavigationUI#setupWithNavController(androidx.appcompat.widget
.Toolbar,%20androidx.navigation.NavController,%20androidx.navigation.ui.AppBarConfiguration))
from your main activity's onCreate method, as shown below:
Kotlin (#kotlin)Java
(#java)
Action bar
To add navigation support to the default action bar, call
setupActionBarWithNavController()
(/reference/androidx/navigation/ui/NavigationUI#setupActionBarWithNavController(androidx.appcom
pat.app.AppCompatActivity,%20androidx.navigation.NavController,%20androidx.navigation.ui.AppBar
Configuration))
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() :
Kotlin (#kotlin)Java
(#java)
AppBarConfiguration appBarConfiguration;
NavHostFragment navHostFragment = supportFragmentManager.findFragmen
NavController navController = navHostFragment.getNavController();
appBarConfiguration = new AppBarConfiguration.Builder(navController.
NavigationUI.setupActionBarWithNavController(this, navController, ap
Kotlin (#kotlin)Java
(#java)
@Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.i
return NavigationUI.navigateUp(navController, appBarConfiguration)
|| super.onSupportNavigateUp();
}
As an example, one of your destinations may use a standard Toolbar , while another uses
an AppBarLayout to create a more complex app bar with tabs, as shown in figure 2.
Figure 2. Two app bar variations. On the left, a standard Toolbar . On the right, an AppBarLayout with
a Toolbar and tabs.
To implement this example within your destination fragments using NavigationUI , first
define the app bar in each of your fragment layouts, beginning with the destination
fragment that uses a standard toolbar:
<LinearLayout>
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
... />
...
</LinearLayout>
Next, define the destination fragment that uses an app bar with tabs:
<LinearLayout>
<com.google.android.material.appbar.AppBarLayout
... />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
... />
<com.google.android.material.tabs.TabLayout
... />
</com.google.android.material.appbar.AppBarLayout>
...
</LinearLayout>
The navigation configuration logic is the same for both of these fragments, except that
you should call setupWithNavController()
(/reference/androidx/navigation/ui/NavigationUI#setupWithNavController(androidx.appcompat.widget
.Toolbar,androidx.navigation.NavController,androidx.navigation.ui.AppBarConfiguration))
from within each fragment's onViewCreated() method, instead of initializing them from
the activity:
Kotlin (#kotlin)Java
(#java)
@Override
public void onViewCreated(@NonNull View view,
@Nullable Bundle savedInstanceState) {
NavController navController = Navigation.findNavController(view);
AppBarConfiguration appBarConfiguration =
new AppBarConfiguration.Builder(navController.getGraph()).bu
Toolbar toolbar = view.findViewById(R.id.toolbar);
NavigationUI.setupWithNavController(
toolbar, navController, appBarConfiguration);
}
Note: Placing the top app bar into the destination fragment layout will result in the app bar animating
with the rest of the layout during fragment transitions when a fragment transition is set.
Tie destinations to menu items
NavigationUI also provides helpers for tying destinations to menu-driven UI
components. NavigationUI contains a helper method, onNavDestinationSelected()
(/reference/androidx/navigation/ui/NavigationUI#onnavdestinationselected), which takes a
MenuItem (/reference/android/view/MenuItem) along with the NavController
(/reference/androidx/navigation/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 :
<fragment android:id="@+id/details_page_fragment"
android:label="@string/details"
android:name="com.example.android.myapp.DetailsFragment" />
<item
android:id="@+id/details_page_fragment"
android:icon="@drawable/ic_details"
android:title="@string/details" />
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 in the
following example:
Kotlin (#kotlin)Java
(#java)
@Override
public boolean onOptionsItemSelected(MenuItem item) {
NavController navController = Navigation.findNavController(this, R.i
return NavigationUI.onNavDestinationSelected(item, 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 .
in the app bar or when the user swipes a finger from the left edge of the screen.
Figure 3. An open drawer displaying a navigation menu.
The drawer icon is displayed on all top-level destinations (#appbarconfiguration) that use a
DrawerLayout .
For example, the following layout uses a DrawerLayout with two child views: a
NavHostFragment (/reference/androidx/navigation/fragment/NavHostFragment) to contain the
main content and a NavigationView
(/reference/com/google/android/material/navigation/NavigationView) for the contents of the
navigation drawer.
<!-- Layout to contain contents of main body of screen (drawer will slide
<androidx.fragment.app.FragmentContainerView
android:name="androidx.navigation.fragment.NavHostFragment"
android:id="@+id/nav_host_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
</androidx.drawerlayout.widget.DrawerLayout>
Kotlin (#kotlin)Java
(#java)
AppBarConfiguration appBarConfiguration =
new AppBarConfiguration.Builder(navController.getGraph())
.setDrawerLayout(drawerLayout)
.build();
Note: When using NavigationUI, the top app bar (#top-app-bar) helpers automatically transition
between the drawer icon and the Up icon as the current destination changes. You don't need to use
ActionBarDrawerToggle (/reference/androidx/appcompat/app/ActionBarDrawerToggle).
Next, in your main activity class, call setupWithNavController()
(/reference/androidx/navigation/ui/NavigationUI#setupWithNavController(com.google.android.materia
l.navigation.NavigationView,%20androidx.navigation.NavController))
from your main activity's onCreate() method, as shown below:
Kotlin (#kotlin)Java
(#java)
Note: Setting up the navigation drawer requires that you also set up your navigation graph and menu
xml as described in Tie destinations to menu items (/guide/navigation/navigation-ui#Tie-navdrawer).
Bottom navigation
NavigationUI can also handle bottom navigation. When a user selects a menu item, the
NavController calls onNavDestinationSelected()
(/reference/androidx/navigation/ui/NavigationUI#onNavDestinationSelected(android.view.MenuItem,%
20androidx.navigation.NavController))
and automatically updates the selected item in the bottom navigation bar.
Figure 4. A bottom navigation bar.
To create a bottom navigation bar in your app, first define the bar in your main activity, as
shown below:
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_nav"
app:menu="@menu/menu_bottom_nav" />
Kotlin (#kotlin)Java
(#java)
Note: Setting up bottom navigation requires that you also set up your navigation graph and menu xml
as described in Tie destinations to menu items (/guide/navigation/navigation-ui#Tie-navdrawer).
For a comprehensive example that includes bottom navigation, see the Android
Architecture Components Advanced Navigation Sample
(https://github.com/android/architecture-components-
samples/tree/main/NavigationAdvancedSample)
on GitHub.
Kotlin (#kotlin)Java
(#java)
navController.addOnDestinationChangedListener(new NavController.OnDestin
@Override
public void onDestinationChanged(@NonNull NavController controller,
@NonNull NavDestination destination, @Nullable Bundle argumen
if(destination.getId() == R.id.full_screen_destination) {
toolbar.setVisibility(View.GONE);
bottomNavigationView.setVisibility(View.GONE);
} else {
toolbar.setVisibility(View.VISIBLE);
bottomNavigationView.setVisibility(View.VISIBLE);
}
}
});
Argument-based listeners
As an alternative, you can also use arguments with default values within the navigation
graph, which can be used by the appropriate UI controller to update its state. For
example, rather than base the logic in the OnDestinationChangedListener on the
destination ID as per the previous example, we can create an argument in the NavGraph :
<argument
android:name="ShowAppBar"
android:defaultValue="true"
Kotlin (#kotlin)Java
(#java)
navController.addOnDestinationChangedListener(
new NavController.OnDestinationChangedListener() {
@Override
public void onDestinationChanged(
@NonNull NavController controller,
@NonNull NavDestination destination,
@Nullable Bundle arguments
) {
boolean showAppBar = false;
if (arguments != null) {
showAppBar = arguments.getBoolean("ShowAppBar", fals
}
if(showAppBar) {
appBar.setVisibility(View.VISIBLE);
} else {
appBar.setVisibility(View.GONE);
}
}
}
);
The NavController (/reference/kotlin/androidx/navigation/NavController) invokes this callback
whenever the navigation destination changes. The Activity can now update the state or
visibility of the UI components that it owns based upon the arguments received in the
callback.
One advantage of this approach is that the Activity sees only the arguments in the
navigation graph and doesn't know individual Fragment roles and responsibilities.
Similarly, the individual fragments do not know about the containing Activity and the UI
components that it owns.
Additional resources
To learn more about navigation, see the following additional resources.
Samples
Android Architecture Components Basic Navigation Sample
(https://github.com/android/architecture-components-
samples/tree/main/NavigationBasicSample)
Codelabs
Navigation codelab
(https://codelabs.developers.google.com/codelabs/android-navigation/index.html?
index=..%2F..%2Findex#0)
Blog posts
LiveData with SnackBar, Navigation and other events (the SingleLiveEvent case)
(https://medium.com/androiddevelopers/livedata-with-snackbar-navigation-and-other-events-
the-singleliveevent-case-ac2622673150)
Videos
10 Best Practices for Moving to a Single Activity
(https://www.youtube.com/watch?v=9O1D_Ytk0xg)
Single Activity: Why, When, and How (Android Dev Summit '18)
(https://www.youtube.com/watch?v=2k8x8V77CrU)
Android Jetpack: manage UI navigation with Navigation Controller (Google I/O '18)
(https://www.youtube.com/watch?v=8GCXtCjtg40)
Content and code samples on this page are subject to the licenses described in the Content License
(/license). Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.