0% found this document useful (0 votes)
46 views

Connect UI Components To NavController Using NavigationUI - Android Developers

Uploaded by

mywire.ac.01
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
46 views

Connect UI Components To NavController Using NavigationUI - Android Developers

Uploaded by

mywire.ac.01
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 20

Connect UI components to

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.

Top app bar


The top app bar (https://material.io/design/components/app-bars-top.html) provides a consistent
place along the top of your app for displaying information and actions from the current
screen.

Figure 1. A screen displaying a top app bar.

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.

A top-level destination is the root, or highest level destination, in a set of hierarchically-


related destinations. Top-level destinations do not display an Up button in the top app bar
because there is no higher level destination. By default, the start destination of your app
is the only top-level destination.

When the user is at a top-level destination, the Navigation button becomes a drawer icon

if the destination uses a DrawerLayout . If the destination doesn't use a DrawerLayout ,


the Navigation button is hidden. When the user is on any other destination, the Navigation
button appears as an Up button

. 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" />

Next, call setupWithNavController()


(/reference/androidx/navigation/ui/NavigationUI#setupWithNavController(androidx.appcompat.widget
.Toolbar,androidx.navigation.NavController,androidx.navigation.ui.AppBarConfiguration))
from your main activity's onCreate() method, as shown in the following example:
Kotlin (#kotlin)Java
( )

NavController navController = Navigation.findNavController(this, R.i


AppBarConfiguration appBarConfiguration =
new AppBarConfiguration.Builder(navController.getGraph()).bu
Toolbar toolbar = findViewById(R.id.toolbar);
NavigationUI.setupWithNavController(
toolbar, navController, appBarConfiguration);

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) {
...

NavHostFragment navHostFragment = (NavHostFragment) supportFragmentM


NavController navController = navHostFragment.getNavController();
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Bu
.setFallbackOnNavigateUpListener(::onSupportNavigateUp)
.build();
Toolbar toolbar = findViewById(R.id.toolbar);
NavigationUI.setupWithNavController(
toolbar, navController, appBarConfiguration);
}

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)

CollapsingToolbarLayout layout = findViewById(R.id.collapsing_toolba


Toolbar toolbar = findViewById(R.id.toolbar);
NavHostFragment navHostFragment = supportFragmentManager.findFragmen
NavController navController = navHostFragment.getNavController();
AppBarConfiguration appBarConfiguration =
new AppBarConfiguration.Builder(navController.getGraph()).bu
NavigationUI.setupWithNavController(layout, toolbar, navController,

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

Next, override onSupportNavigateUp() to handle Up navigation:

Kotlin (#kotlin)Java
(#java)

@Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.i
return NavigationUI.navigateUp(navController, appBarConfiguration)
|| super.onSupportNavigateUp();
}

Support app bar variations


Adding the top app bar to your activity works well when the app bar’s layout is similar for
each destination in your app. If, however, your top app bar changes substantially across
destinations, then consider removing the top app bar from your activity and defining it in
each destination fragment, instead.

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 .

Add a navigation drawer


The navigation drawer is a UI panel that shows your app's main navigation menu. The
drawer appears when the user touches the drawer icon

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 .

To add a navigation drawer, first declare a DrawerLayout


(/reference/androidx/drawerlayout/widget/DrawerLayout) as the root view. Inside the
DrawerLayout , add a layout for the main UI content and another view that contains the
contents of the navigation drawer.

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.

<?xml version="1.0" encoding="utf-8"?>


<!-- Use DrawerLayout as root container for activity -->
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.andro
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">

<!-- 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" />

<!-- Container for contents of drawer - use NavigationView to make config


<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true" />

</androidx.drawerlayout.widget.DrawerLayout>

Next, connect the DrawerLayout (/reference/androidx/drawerlayout/widget/DrawerLayout) to


your navigation graph by passing it to AppBarConfiguration , as shown in the following
example:

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)

NavHostFragment navHostFragment = supportFragmentManager.findFragmen


NavController navController = navHostFragment.getNavController();
NavigationView navView = findViewById(R.id.nav_view);
NavigationUI.setupWithNavController(navView, navController);

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).

Starting in Navigation 2.4.0-alpha01 (/jetpack/androidx/releases/navigation#2.4.0-alpha01), the


state of each menu item is saved and restored when you use setupWithNavController .

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" />

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)

NavHostFragment navHostFragment = supportFragmentManager.findFragmen


NavController navController = navHostFragment.getNavController();
BottomNavigationView bottomNav = findViewById(R.id.bottom_nav);
NavigationUI.setupWithNavController(bottomNav, navController);

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).

Starting in Navigation 2.4.0-alpha01 (/jetpack/androidx/releases/navigation#2.4.0-alpha01), the


state of each menu item is saved and restored when you use setupWithNavController .

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.

Listen for navigation events


Interacting with the NavController (/reference/androidx/navigation/NavController) is the
primary method for navigating between destinations. The NavController is responsible
for replacing the contents of the NavHost (/reference/androidx/navigation/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 OnDestinationChangedListener interface that is called when


the NavController 's current destination
(/reference/androidx/navigation/NavController#getCurrentDestination%28%29) or its arguments
change. A new listener can be registered via the addOnDestinationChangedListener()
(/reference/androidx/navigation/NavController#addOnDestinationChangedListener%28androidx.navig
ation.NavController.OnDestinationChangedListener%29)
method. Note that when calling addOnDestinationChangedListener() , if the current
destination exists, it's immediately sent to your listener.

NavigationUI uses OnDestinationChangedListener to make these common UI


components navigation-aware. Note, however, that you can also use
OnDestinationChangedListener on its own to make any custom UI or business logic
aware of navigation events.
As an example, you might have common UI elements that you intend to show in some
areas of your app while hiding them in others. Using your own
OnDestinationChangedListener , you can selectively show or hide these UI elements
based on the target destination, as shown in the following example:

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"

This argument isn't used when navigating to the destination


(/guide/navigation/navigation-navigate), but rather as a way to attach additional information
to the destination by using the defaultValue . In this case, the value indicates whether
the app bar should be shown when on this destination.

We can now add an OnDestinationChangedListener in the Activity :

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)

Android Architecture Components Advanced Navigation Sample


(https://github.com/android/architecture-components-
samples/tree/main/NavigationAdvancedSample)

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.

Last updated 2024-02-20 UTC.

You might also like