You are on page 1of 33

Principles of navigation

Navigation between different screens and apps is a core part of the user experience. The following
principles set a baseline for a consistent and intuitive user experience across apps. The Navigation
component is designed to implement these principles by default, ensuring that users can apply the
same heuristics and patterns in navigation as they move between apps.

Fixed start destination


Every app you build has a fixed start destination. This is the first screen the user sees when they
launch your app from the launcher. This destination is also the last screen the user sees when
they return to the launcher after pressing the Back button. Let’s take a look at the Sunflower
app as an example.

Figure 1. The List Screen is the Sunflower app's start destination.

When launching the Sunflower app from the launcher, the first screen that a user sees is
the List Screen, the list of plants in their garden. This is also the last screen they see before
exiting the app. If they press the Back button from the list screen, they navigate back to the
launcher.

Note: An app might have a one-time setup or series of login screens. These conditional screens should not
be considered start destinations because users see these screens only in certain cases.

Navigation state is represented as a stack of destinations


When your app is first launched, a new task is created for the user, and app displays its start
destination. This becomes the base destination of what is known as the back stack and is the
basis for your app’s navigation state. The top of the stack is the current screen, and the
previous destinations in the stack represent the history of where you've been. The back stack
always has the start destination of the app at the bottom of the stack.
Operations that change the back stack always operate on the top of the stack, either by pushing
a new destination onto the top of the stack or popping the top-most destination off the stack.
Navigating to a destination pushes that destination on top of the stack.

The Navigation component manages all of your back stack ordering for you, though you can
also choose to manage the back stack yourself.

Up and Back are identical within your app's task

Figure 2. The Up and Back buttons

The Back button appears in the system navigation bar at the bottom of the screen and is used
to navigate in reverse-chronological order through the history of screens the user has recently
worked with. When you press the Back button, the current destination is popped off the top of
the back stack, and you then navigate to the previous destination.

The Up button appears in the app bar at the top of the screen. Within your app's task, the Up
and Back buttons behave identically.

The Up button never exits your app


If a user is at the app's start destination, then the Up button does not appear, because the Up
button never exits the app. The Back button, however, is shown and does exit the app.

When your app is launched using a deep link on another app's task, Up transitions users back
to your app’s task and through a simulated back stack and not to the app that triggered the
deep link. The Back button, however, does take you back to the other app.

Deep linking simulates manual navigation


Whether deep linking or manually navigating to a specific destination, you can use the Up
button to navigate through destinations back to the start destination.

When deep linking to a destination within your app’s task, any existing back stack for your
app’s task is removed and replaced with the deep-linked back stack.

Using the Sunflower app again as an example, let’s assume that the user had previously
launched the app from the launcher screen and navigated to the detail screen for an apple.
Looking at the Recents screen would indicate that a task exists with the top most screen being
the detail screen for the Apple.
Figure 3. User navigation through the Sunflower app and the resulting back stack.

At this point, the user can tap the Home button to put the app in the background. Next, let’s say
this app has a deep link feature that allows users to launch directly into a specific plant detail
screen by name. Opening the app via this deep link completely replaces the current Sunflower
back stack shown in figure 3 with a new back stack, as shown in figure 4:

Figure 4. Following a deep link replaces the existing back stack for the Sunflower app.

Notice that the Sunflower back stack is replaced by a synthetic back stack with the avocado detail
screen at the top. The My Garden screen, which is the start destination, was also added to the
back stack. The original Sunflower back stack is gone, including the app's knowledge that the
user was on the Apple details screen before. All of this is important because the synthetic back
stack must be realistic. It should match a back stack that could have been achieved by
organically navigating through the app.

To meet this need, the synthetic back stack that is created is a simplified one based on
the NavGraph. For a simple NavGraph without nesting, this will consist of the start destination and
the deep link destination. For more complex, nested navigation graphs, the synthetic back stack
will also contain the start destinations of any nested graphs that are ancestors of the deep link
destination.
The Navigation component supports deep linking and recreates a realistic back stack for you
when linking to any destination in your navigation graph.

Navigation
bookmark_border
Navigation refers to the interactions that let users navigate across, into, and back out from the
different pieces of content within your app.

Android Jetpack's Navigation component includes the Navigation library, Safe Args Gradle
plug-in, and tooling to help you implement app navigation. The Navigation component handles
diverse navigation use cases, from straightforward button clicks to more complex patterns,
such as app bars and the navigation drawer.

Important: The Navigation component also ensures a consistent and predictable user
experience by adhering to an established set of principles.

Key concepts
The following table provides an overview of the three key concepts in navigation and the main
types that you use to implement them.

Concept Purpose Type

Host A UI element that contains the current navigation destination. That is, • Compose: NavHost
when a user navigates through an app, the app essentially swaps
• Fragments: NavHostFragment
destinations in and out of the navigation host.
Graph A data structure that defines all the navigation destinations within the NavGraph
app and how they connect together.
Controller The central coordinator for managing navigation between destinations. NavController
The controller offers methods for navigating between destinations,
handling deep links, managing the back stack, and more.

Important: Whether you are using Compose, views, or a custom UI framework, these three
concepts always apply when implementing navigation. However, the specific ways in which you
use them can differ.

Benefits and features


The Navigation component provides a number of other benefits and features, including the
following:

• Animations and transitions: Provides standardized resources for animations and


transitions.

• Deep linking: Implements and handles deep links that take the user directly to a
destination.

• UI patterns: Supports patterns such as navigation drawers and bottom navigation with
minimal additional work.
• Type safety: Includes the Safe Args Gradle plugin which provides type safety when
navigating and passing data between destinations.

• ViewModel support: Enables scoping a ViewModel to a navigation graph to share UI-


related data between the graph's destinations.

• Fragment transactions: Fully supports and handles fragment transactions.

• Back and up: Handles back and up actions correctly by default.

Note: If you are using XML for your navigation graphs, use Android Studio's Navigation
Editor to view and edit your graphs.
Note: Android 13 introduces predictive back navigation, which works with the Navigation
component for Android devices. Implement predictive back navigation in your app as soon as
possible. Otherwise, users might experience unexpected behavior in a future Android release.

Set up your environment


To include navigation support in your project, add the following dependencies to your
app's build.gradle file:

For information on adding other architecture components to your project, see Add components
to your project.

Next steps
For more documentation and resources related to the Navigation component, see the following
resources.
Detailed guides

For more information on how to implement a navigation host and NavController, as well as detail
on how they interact with Compose and other UI frameworks, see the following guides:

• Create a navigation controller: Outlines how to create a NavController.

• Create your navigation graph: Details how to create a navigation host and a navigation
graph.

• Navigate to a destination: Demonstrates how to use a NavController to move between the


destinations in your graph.

Codelabs

• Learn Jetpack Navigation

• Fragments and the Navigation Component

• Build an adaptive app with dynamic navigation

Videos

• Navigating navigation

• 10 best practices for moving to a single activity

• Single activity: Why, when, and hHow (Android Dev Summit '18)

• Android Jetpack: Manage UI navigation with navigation controller (Google I/O '18)

Samples

GITHUB

Jetsnack sample
Jetsnack is a sample snack ordering app built with Jetpack Compose. To try out this sample app,
use the latest stable version of Android Studio. You can clone this repository or import the
project from Android Studio following the steps here. This

GITHUB

Jetchat sample

Jetchat is a sample chat app built with Jetpack Compose. To try out this sample app, use the
latest stable version of Android Studio. You can clone this repository or import the project from
Android Studio following the steps here. This sample
GITHUB

Architecture

These samples showcase different architectural approaches to developing Android apps. In its
different branches you'll find the

APP NAVIGATION

In Kotlin, you can implement app navigation using various techniques and frameworks, but one
popular approach is to use the Jetpack Navigation Component provided by Android Jetpack.
This component simplifies the implementation of navigation in your app by providing a
declarative way to define and navigate between destinations in your app's navigation graph.

Here's a basic overview of how to implement app navigation using the Navigation Component
in Kotlin:

1. Add Dependencies: Add the Navigation dependencies to your build.gradle file:

2. Create Navigation Graph: Create a new XML file for your navigation graph (e.g.,
nav_graph.xml) under the res/navigation directory. Define your app's destinations and
connections between them in this graph.

3. Set Up NavHostFragment: In your activity's layout XML file, add a NavHostFragment to define
the area where your destinations will be displayed:
4. Navigate Between Destinations: Use the NavController to navigate between destinations
programmatically:

5. Handle Navigation Events: You can set up navigation events listeners to perform actions
when navigation events occur, such as updating the UI or executing business logic:

6. Pass Data Between Destinations: You can pass data between destinations using Safe Args or
manually passing arguments via the Bundle:

7. Handle Up and Back Navigation: Ensure that the Up and Back navigation works correctly by
configuring the ActionBar or Toolbar:
This is a basic outline of implementing app navigation using the Navigation Component in
Kotlin. You can further customize your navigation setup based on your app's requirements,
such as adding animations, deep linking, or handling deep links.

Working with the AppBar


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

wnership of the app bar varies depending on the needs of your app. When using fragments,
the app bar can be implemented as an ActionBar that is owned by the host activity or a toolbar
within your fragment's layout.

If all your screens use the same app bar that's always at the top and spans the width of the
screen, use a theme-provided action bar hosted by the activity. Using theme app bars helps to
maintain a consistent look and provides a place to host option menus and an Up button.

Use a toolbar hosted by the fragment if you want more control over the size, placement, and
animation of the app bar across multiple screens. For example, you might need a collapsing
app bar or one that spans only half the width of the screen and is vertically centered.

Different situations require different approaches for things like inflating menus and responding
to user interaction. Understanding the different approaches and employing the best one for
your app saves you time and helps ensure that your app functions properly.
The examples in this topic reference an ExampleFragment that contains an editable profile. The
fragment inflates the following XML-defined menu in its app bar:

<!-- sample_menu.xml -->


<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<item
android:id="@+id/action_settings"
android:icon="@drawable/ic_settings"
android:title="@string/settings"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_done"
android:icon="@drawable/ic_done"
android:title="@string/done"
app:showAsAction="ifRoom|withText"/>

</menu>

The menu contains two options: one for navigating to a profile screen and one to save any
profile changes made.

Activity-owned app bar


The app bar is most commonly owned by the host activity. When the app bar is owned by an
activity, fragments can interact with the app bar by overriding framework methods that are
called during fragment creation.

Note: This guidance applies only when the app bar is owned by the activity. If your app bar is a toolbar that's
included in a fragment layout, see the Fragment-owned app bar section.

Register with activity

You must inform the system that your app bar fragment is participating in the population of the
options menu. To do this, call setHasOptionsMenu(true) in your fragment's onCreate(Bundle) method,
as shown in the following example:
class ExampleFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
}

setHasOptionsMenu(true) tells the system that your fragment wants to receive menu-related
callbacks. When a menu-related event occurs, like a click, the event-handling method is first
called on the activity before being called on the fragment.
However, don't rely on this order in your application logic. If the same activity hosts multiple
fragments, each fragment can supply menu options, in which case the callback order depends
on the order in which the fragments are added.

Inflate the menu

To merge your menu into the app bar's options menu, override onCreateOptionsMenu() in your
fragment. This method receives the current app bar menu and a MenuInflater as parameters. Use
the menu inflater to create an instance of your fragment's menu, and then merge it into the
current menu, as shown in the following example:

class ExampleFragment : Fragment() {


...
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.sample_menu, menu)
}
}

Figure 2 shows the updated menu.

Handle click events

Every activity and fragment that participates in the options menu can respond to touches. The
fragment's onOptionsItemSelected() receives the selected menu item as a parameter and returns a
boolean to indicate whether the touch is consumed. Once an activity or fragment
returns true from onOptionsItemSelected(), no other participating fragments receive the callback.

In your implementation of onOptionsItemSelected(), use a switch statement on the itemId of the


menu item. If the selected item is yours, handle the touch appropriately and return true to
indicate that the click event is handled. If the selected item isn't yours, call
the super implementation. By default, the super implementation returns false to let menu
processing continue.
class ExampleFragment : Fragment() {
...
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_settings -> {
// Navigate to settings screen.
true
}
R.id.action_done -> {
// Save profile changes.
true
}
else -> super.onOptionsItemSelected(item)
}
}
}

Note: In your Fragment, only handle menu items added through its onCreateOptionsMenu() call. When
using an activity-owned app bar, handle click events in the activity for the Up button and for menu items that
aren't added by a Fragment.

Dynamically modify the menu

Place the logic to hide or show a button or change the icon in onPrepareOptionsMenu(). This
method is called right before the menu is shown.

Continuing with the previous example, the Save button should be invisible until the user begins
editing, and it should disappear after the user saves. Adding this logic
to onPrepareOptionsMenu() makes the menu present correctly:

class ExampleFragment : Fragment() {


...
override fun onPrepareOptionsMenu(menu: Menu){
super.onPrepareOptionsMenu(menu)
val item = menu.findItem(R.id.action_done)
item.isVisible = isEditing
}
}

When you need to update the menu, such as when a user presses the Edit button to edit the
profile info, call invalidateOptionsMenu() on the host activity to request that the system
call onCreateOptionsMenu(). After invalidation, you can make the updates
in onCreateOptionsMenu(). Once the menu inflates, the system calls onPrepareOptionsMenu() and
updates the menu to reflect the fragment's current state.
class ExampleFragment : Fragment() {
...
fun updateOptionsMenu() {
isEditing = !isEditing
requireActivity().invalidateOptionsMenu()
}
}

Fragment-owned app bar


If most screens in your app don't need an app bar, or if one screen needs a different app bar
than the others, you can add a Toolbar to your fragment layout. Though you can add
a Toolbar anywhere within your fragment's view hierarchy, you generally keep it at the top of
the screen. To use the Toolbar in your fragment, provide an ID and obtain a reference to it in
your fragment, as with any other view. You can also consider animating the toolbar
using CoordinatorLayout behaviors.

<androidx.appcompat.widget.Toolbar
android:id="@+id/myToolbar"
... />

When using a fragment-owned app bar, Google recommends using the Toolbar APIs directly.
Do not use setSupportActionBar() and the Fragment menu APIs, which are appropriate only for
activity-owned app bars.

Inflate the menu

The Toolbar convenience method inflateMenu(int) takes the ID of a menu resource as a parameter.
To inflate an XML menu resource into your toolbar, pass the resId to this method, as shown in
the following example:

class ExampleFragment : Fragment() {


...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
...
viewBinding.myToolbar.inflateMenu(R.menu.sample_menu)
}
}

To inflate another XML menu resource, call the method again with the resId of the new menu.
The new menu items are added to the menu, and the existing menu items are not modified or
removed.

If you want to replace the existing menu set, clear the menu before calling inflateMenu(int) with
the new menu ID, as shown in the following example:

class ExampleFragment : Fragment() {


...
fun clearToolbarMenu() {
viewBinding.myToolbar.menu.clear()
}
}

Handle click events

You can pass an OnMenuItemClickListener directly to the toolbar using


the setOnMenuItemClickListener() method. This listener is invoked when the user selects a menu
item from the action buttons presented at the end of the toolbar or the associated overflow.
The selected MenuItem is passed to the listener's onMenuItemClick() method and can be used to
consume the action, as shown in the following example:
class ExampleFragment : Fragment() {
...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
...
viewBinding.myToolbar.setOnMenuItemClickListener {
when (it.itemId) {
R.id.action_settings -> {
// Navigate to settings screen.
true
}
R.id.action_done -> {
// Save profile changes.
true
}
else -> false
}
}
}
}

Dynamically modify the menu

When your fragment owns the app bar, you can modify the Toolbar at runtime exactly like any
other view.

Continuing with the previous example, the Save menu option should be invisible until the user
begins editing, and it should disappear again when tapped:

class ExampleFragment : Fragment() {


...
fun updateToolbar() {
isEditing = !isEditing

val saveItem = viewBinding.myToolbar.menu.findItem(R.id.action_done)


saveItem.isVisible = isEditing

}
}

Add a navigation icon

If present, the navigation button appears at the start of the toolbar. Setting a navigation icon
on the toolbar makes it visible. You can also set a navigation-specific onClickListener() that is
called whenever the user clicks on the navigation button, as shown in the following example:

class ExampleFragment : Fragment() {


...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
...
myToolbar.setNavigationIcon(R.drawable.ic_back)

myToolbar.setNavigationOnClickListener { view ->


// Navigate somewhere.
}
}
}
Understanding and Integrating
Navigation Drawer in Android using
Kotlin
The Navigation Drawer is a common UI component in Android apps that provides
a slide-in menu from the left side of the screen. It’s typically used to house the
main navigation options or other important features of the application. This
article will cover what a Navigation Drawer is, why it’s important, and how to
integrate it into an Android app using Kotlin.

What is a Navigation Drawer?


A Navigation Drawer is a user interface pattern that allows users to access the
primary features or sections of an application by sliding the drawer from the left
edge of the screen. It usually contains icons or labels representing various
destinations or actions within the app. The Navigation Drawer enhances user
experience by providing quick access to different parts of the application while
keeping the main screen clutter-free.

Why do we need a Navigation Drawer in Android?


1. Enhanced User Experience: Navigation Drawers provide an intuitive and
consistent way for users to access different sections of an app, improving
overall user experience.

2. Efficient Use of Space: It allows efficient use of screen space by hiding


the navigation options when not needed, providing a cleaner and more
focused interface.

3. Organized Navigation: Applications with multiple sections or features


can organize them neatly within the Navigation Drawer, making it easier
for users to find what they’re looking for.

4. Consistency Across the App: When implemented correctly, the


Navigation Drawer ensures a consistent navigation pattern throughout
the app, enhancing usability and reducing confusion.

Integration :-
Creating a Navigation Drawer in an Android app using Kotlin involves several
steps. In this example, I’ll guide you through the process to integrate a simple
Navigation Drawer.

1. Setup
Firstly, ensure you have the required dependencies in your build.gradle (Module:
app):

implementation 'com.google.android.material:material:latest_version'

2. Create the Drawer Layout


Inside res/layout/fragment_main.xml:

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


<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Main content -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- Your main content here -->
</LinearLayout>
<!-- Navigation View -->
<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"
app:menu="@menu/drawer_menu"/>
</androidx.drawerlayout.widget.DrawerLayout>

3. Create a Menu for the Navigation Drawer


Inside res/menu/menu.xml:

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


<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="co.vecmocon.MainActivity">
<item
android:id="@+id/itemServiceHistory"
android:icon="@drawable/ic_service_history"
android:title="@string/service_history" />
<item
android:id="@+id/itemPayment"
android:icon="@drawable/ic_payment"
android:title="@string/payments" />
<item
android:id="@+id/itemSupport"
android:icon="@drawable/ic_support"
android:title="@string/support" />
</menu>

4. Implement Drawer in Kotlin


In your HomeFragment.kt:

class HomeFragment : Fragment() {


private lateinit var actionBarToggle: ActionBarDrawerToggle
private val binding by viewBinding(FragmentHomeBinding::bind)

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {


super.onViewCreated(view, savedInstanceState)
requireActivity().onBackPressedDispatcher.addCallback(this) {
requireActivity().finish()
}

binding.apply {
actionBarToggle = ActionBarDrawerToggle(requireActivity(), drawerLayout, 0,
0)
drawerLayout.addDrawerListener(actionBarToggle)
// Display the hamburger icon to launch the drawer
// Call syncState() on the action bar so it'll automatically change to the
back button when the drawer layout is open
actionBarToggle.syncState()

ivMenuHF.setOnClickListener(this@HomeFragment)

navView.setNavigationItemSelectedListener { menuItem ->


when (menuItem.itemId) {
R.id.itemServiceHistory -> {

addFragment(FragmentFactory.Screens.SERVICE_HISTORY_FRAGMENT,null)
true
}
R.id.itemPayment -> {
Utils.showToast(requireActivity(), "People")
true
}
R.id.itemSupport -> {
Utils.showToast(requireActivity(),"Settings")
true
}
else -> {
false
}
}
}
}
}

override fun onClick(view: View?) {


super.onClick(view)
when (view?.id) {
R.id.ivMenuHF -> {
binding.drawerLayout.openDrawer(binding.navView)
}
}
}
}

Note: You’ll need to define R.string.service_history,


R.string.payments and R.string.supports in your strings.xml, or replace them with
your preferred strings.

With this, you’ll have a basic Navigation Drawer integrated into your Android app.
Remember to customize the items, actions, and styles as per your app’s
requirements.
Add menus
Menus are a common user interface component in many types of apps. To provide a familiar and
consistent user experience, use the Menu APIs to present user actions and other options in your
activities.

Figure 1. A menu triggered by an icon tap, appearing below the overflow menu icon.

This document shows how to create the three fundamental types of menus or action
presentations on all versions of Android:

Options menu and app bar

The options menu is the primary collection of menu items for an activity. It's where you
place actions that have a global impact on the app, such as "Search," "Compose email,"
and "Settings."

See the Create an options menu section.

Context menu and contextual action mode

A context menu is a floating menu that appears when the user performs a touch & hold
on an element. It provides actions that affect the selected content or context frame.

The contextual action mode displays action items that affect the selected content in a bar
at the top of the screen and lets the user select multiple items.

See the Create a contextual menu section.

Popup menu

A popup menu displays a vertical list of items that's anchored to the view that invokes
the menu. It's good for providing an overflow of actions that relate to specific content or
to provide options for the second part of a command. Actions in a popup menu don't
directly affect the corresponding content—that's what contextual actions are for. Rather,
the popup menu is for extended actions that relate to regions of content in your activity.

See the Create a popup menu section.


Define a menu in XML
For all menu types, Android provides a standard XML format to define menu items. Instead of
building a menu in your activity's code, define a menu and all its items in an XML menu
resource. You can then inflate the menu resource—loading it as a Menu object—in your activity
or fragment.

Using a menu resource is good practice for the following reasons:

• It's easier to visualize the menu structure in XML.

• It separates the content for the menu from your app's behavioral code.

• It lets you create alternative menu configurations for different platform versions, screen
sizes, and other configurations by leveraging the app resources framework.

To define a menu, create an XML file inside your project's res/menu/ directory and build the
menu with the following elements:

<menu>

Defines a Menu, which is a container for menu items. A <menu> element must be the root
node for the file, and it can hold one or more <item> and <group> elements.

<item>

Creates a MenuItem, which represents a single item in a menu. This element can contain a
nested <menu> element to create a submenu.

<group>

An optional, invisible container for <item> elements. It lets you categorize menu items so
they share properties, such as active state and visibility. For more information, see
the Create a menu group section.

Here's an example menu named game_menu.xml:

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


<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/new_game"
android:icon="@drawable/ic_new_game"
android:title="@string/new_game"
app:showAsAction="ifRoom"/>
<item android:id="@+id/help"
android:icon="@drawable/ic_help"
android:title="@string/help" />
</menu>

The <item> element supports several attributes you can use to define an item's appearance and
behavior. The items in the preceding menu include the following attributes:

android:id

A resource ID that's unique to the item, which lets the app recognize the item when the
user selects it.

android:icon
A reference to a drawable to use as the item's icon.

android:title

A reference to a string to use as the item's title.

android:showAsAction

The specification for when and how this item appears as an action item in the app bar.

These are the most important attributes you use, but there are many more available. For
information about all the supported attributes, see the Menu resource documentation.

You can add a submenu to an item in any menu by adding a <menu> element as the child of
an <item>. Submenus are useful when your app has a lot of functions that can be organized into
topics, like items in a PC app's menu bar—such as File, Edit, and View. See the following
example:

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


<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/file"
android:title="@string/file" >
<!-- "file" submenu -->
<menu>
<item android:id="@+id/create_new"
android:title="@string/create_new" />
<item android:id="@+id/open"
android:title="@string/open" />
</menu>
</item>
</menu>

To use the menu in your activity, _inflate_ the menu resource, converting the XML resource into
a programmable object using MenuInflater.inflate(). The following sections show how to inflate a
menu for each menu type.

Create an options menu


The options menu, like the one shown in figure 1, is where you include actions and other
options that are relevant to the current activity context, such as "Search," "Compose email,"
and "Settings."

Figure 2. The Google Sheets app,


showing several buttons, including the action overflow button.

You can declare items for the options menu from your Activity subclass or a Fragment subclass. If
both your activity and your fragments declare items for the options menu, the items are
combined in the UI. The activity's items appear first, followed by those of each fragment, in the
order in which the fragments are added to the activity. If necessary, you can reorder the menu
items with the android:orderInCategory attribute in each <item> you need to move.

To specify the options menu for an activity, override onCreateOptionsMenu(). Fragments provide
their own onCreateOptionsMenu() callback. In this method, you can inflate your menu
resource, defined in XML, into the Menu provided in the callback. This is shown in the following
example:

KotlinJava

override fun onCreateOptionsMenu(menu: Menu): Boolean {


val inflater: MenuInflater = menuInflater
inflater.inflate(R.menu.game_menu, menu)
return true
}

You can also add menu items using add() and retrieve items with findItem() to revise their
properties with MenuItem APIs.

Handle click events

When the user selects an item from the options menu, including action items in the app bar,
the system calls your activity's onOptionsItemSelected() method. This method passes
the MenuItem selected. You can identify the item by calling getItemId(), which returns the unique
ID for the menu item, defined by the android:id attribute in the menu resource or with an integer
given to the add() method. You can match this ID against known menu items to perform the
appropriate action.

KotlinJava

override fun onOptionsItemSelected(item: MenuItem): Boolean {


// Handle item selection.
return when (item.itemId) {
R.id.new_game -> {
newGame()
true
}
R.id.help -> {
showHelp()
true
}
else -> super.onOptionsItemSelected(item)
}
}

When you successfully handle a menu item, return true. If you don't handle the menu item, call
the superclass implementation of onOptionsItemSelected(). The default implementation returns
false.

If your activity includes fragments, the system first calls onOptionsItemSelected() for the activity,
then for each fragment in the order the fragments are added, until one returns true or all
fragments are called.

Tip: If your app contains multiple activities and some of them provide the same options menu, consider creating an
activity that implements only the onCreateOptionsMenu() and onOptionsItemSelected() methods. Then extend
this class for each activity that shares the same options menu. This way, you can manage one set of code for handling
menu actions, and each descendant class inherits the menu behaviors. If you want to add menu items to one of the
descendant activities, override >onCreateOptionsMenu() in that activity.
Call super.onCreateOptionsMenu(menu) so the original menu items are created, then add new menu items
with menu.add(). You can also override the superclass's behavior for individual menu items.

Change menu items at runtime

After the system calls onCreateOptionsMenu(), it retains an instance of the Menu you populate and
doesn't call onCreateOptionsMenu() again unless the menu is invalidated. However,
use onCreateOptionsMenu() only to create the initial menu state and not to make changes during
the activity lifecycle.

If you want to modify the options menu based on events that occur during the activity lifecycle,
you can do so in the onPrepareOptionsMenu() method. This method passes you the Menu object as
it currently exists so you can modify it, such as by adding, removing, or disabling items.
Fragments also provide an onPrepareOptionsMenu() callback.

The options menu is considered always open when menu items are presented in the app bar.
When an event occurs and you want to perform a menu update, call invalidateOptionsMenu() to
request that the system call onPrepareOptionsMenu().

Note: Never change items in the options menu based on the View in focus. When in touch mode—when the user isn't
using a trackball or D-pad—views can't take focus, so never use focus as the basis for modifying items in the options
menu. If you want to provide menu items that are context-sensitive to a View, use a contextual menu as described in the
following section.

Create a contextual menu

Figure 3. A floating context menu.

A contextual menu offers actions that affect a specific item or context frame in the UI. You can
provide a context menu for any view, but they are most often used for items in a RecylerView or
other view collections in which the user can perform direct actions on each item.

There are two ways to provide contextual actions:

• In a floating context menu. A menu appears as a floating list of menu items, similar to a dialog,
when the user performs a touch & hold on a view that declares support for a context menu.
Users can perform a contextual action on one item at a time.
• In the contextual action mode. This mode is a system implementation of ActionMode that displays
a contextual action bar, or CAB, at the top of the screen with action items that affect the selected
item(s). When this mode is active, users can perform an action on multiple items at once, if your
app supports that.

Create a floating context menu

To provide a floating context menu, do the following:

1. Register the View the context menu is associated with by calling registerForContextMenu() and
passing it the View.

If your activity uses a RecyclerView and you want each item to provide the same context
menu, register all items for a context menu by passing
the RecyclerView to registerForContextMenu().

2. Implement the onCreateContextMenu() method in your Activity or Fragment.

When the registered view receives a touch & hold event, the system calls
your onCreateContextMenu() method. This is where you define the menu items, usually by
inflating a menu resource, as in the following example:

KotlinJava

override fun onCreateContextMenu(menu: ContextMenu, v: View,


menuInfo: ContextMenu.ContextMenuInfo) {
super.onCreateContextMenu(menu, v, menuInfo)
val inflater: MenuInflater = menuInflater
inflater.inflate(R.menu.context_menu, menu)
}

MenuInflater lets you inflate the context menu from a menu resource. The callback method
parameters include the View that the user selects and a ContextMenu.ContextMenuInfo object
that provides additional information about the item selected. If your activity has several
views that each provide a different context menu, you might use these parameters to
determine which context menu to inflate.
3. Implement onContextItemSelected(), as shown in the following example. When the user
selects a menu item, the system calls this method so you can perform the appropriate
action.

KotlinJava

override fun onContextItemSelected(item: MenuItem): Boolean {


val info = item.menuInfo as AdapterView.AdapterContextMenuInfo
return when (item.itemId) {
R.id.edit -> {
editNote(info.id)
true
}
R.id.delete -> {
deleteNote(info.id)
true
}
else -> super.onContextItemSelected(item)
}
}
The getItemId() method queries the ID for the selected menu item, which you assign to
each menu item in XML using the android:id attribute, as shown in Define a menu in XML.

When you successfully handle a menu item, return true. If you don't handle the menu
item, pass the menu item to the superclass implementation. If your activity includes
fragments, the activity receives this callback first. By calling the superclass when
unhandled, the system passes the event to the respective callback method in each
fragment, one at a time, in the order each fragment is added, until true or false is
returned. The default implementations for Activity and android.app.Fragment return false, so
always call the superclass when unhandled.

Use the contextual action mode

The contextual action mode is a system implementation of ActionMode that focuses user
interaction toward performing contextual actions. When a user enables this mode by selecting
an item, a contextual action bar appears at the top of the screen to present actions the user can
perform on the selected items. While this mode is enabled, the user can select multiple items, if
your app supports that, and can deselect items and continue to navigate within the activity. The
action mode is disabled and the contextual action bar disappears when the user deselects all
items, taps the Back button, or taps the Done action on the left side of the bar.

Note: The contextual action bar isn't necessarily associated with the app bar. They operate independently, although the
contextual action bar visually overtakes the app bar position.

For views that provide contextual actions, you usually invoke the contextual action mode when
one or both of these two events occurs:

• The user performs a touch & hold on the view.

• The user selects a checkbox or similar UI component within the view.

How your app invokes the contextual action mode and defines the behavior for each action
depends on your design. There are two designs:

• For contextual actions on individual, arbitrary views.

• For batch contextual actions on groups of items in a RecyclerView, letting the user select multiple
items and perform an action on them all.

The following sections describe the setup required for each scenario.

Enable the contextual action mode for individual views

If you want to invoke the contextual action mode only when the user selects specific views, do
the following:

1. Implement the ActionMode.Callback interface as shown in the following example. In its callback
methods, you can specify the actions for the contextual action bar, respond to click events on
action items, and handle other lifecycle events for the action mode.

KotlinJava
private val actionModeCallback = object : ActionMode.Callback {
// Called when the action mode is created. startActionMode() is called.
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
// Inflate a menu resource providing context menu items.
val inflater: MenuInflater = mode.menuInflater
inflater.inflate(R.menu.context_menu, menu)
return true
}

// Called each time the action mode is shown. Always called after
// onCreateActionMode, and might be called multiple times if the mode
// is invalidated.
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
return false // Return false if nothing is done
}

// Called when the user selects a contextual menu item.


override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
return when (item.itemId) {
R.id.menu_share -> {
shareCurrentItem()
mode.finish() // Action picked, so close the CAB.
true
}
else -> false
}
}

// Called when the user exits the action mode.


override fun onDestroyActionMode(mode: ActionMode) {
actionMode = null
}
}

These event callbacks are almost exactly the same as the callbacks for the options menu,
except that each of these also passes the ActionMode object associated with the event. You
can use ActionMode APIs to make various changes to the CAB, such as revising the title and
subtitle with setTitle() and setSubtitle(), which is useful to indicate how many items are
selected.

The preceding sample sets the actionMode variable to null when the action mode is
destroyed. In the next step, see how it's initialized and how saving the member variable
in your activity or fragment can be useful.

2. Call startActionMode() when you want to show the bar, such as when the user performs a touch &
hold on the view.

KotlinJava
someView.setOnLongClickListener { view ->
// Called when the user performs a touch & hold on someView.
when (actionMode) {
null -> {
// Start the CAB using the ActionMode.Callback defined earlier.
actionMode = activity?.startActionMode(actionModeCallback)
view.isSelected = true
true
}
else -> false
}
}

When you call startActionMode(), the system returns the ActionMode created. By saving this
in a member variable, you can make changes to the contextual action bar in response to
other events. In the preceding sample, the ActionMode is used to ensure that
the ActionMode instance isn't recreated if it's already active, by checking whether the
member is null before starting the action mode.

Create a popup menu

Figure 4. A popup menu in the Gmail app, anchored to the overflow


button in the top-right corner.

A PopupMenu is a modal menu anchored to a View. It appears below the anchor view if there is
room, or above the view otherwise. It's useful for the following:

• Providing an overflow-style menu for actions that relate to specific content, such as Gmail's email
headers, shown in figure 4.Note: This isn't the same as a context menu, which is generally for
actions that affect selected content. For actions that affect selected content, use the contextual
action mode or floating context menu.

• Providing a second part of a command sentence, such as a button marked Add that produces a
popup menu with different Add options.

• Providing a menu similar to a Spinner that doesn't retain a persistent selection.

If you define your menu in XML, here's how you can show the popup menu:

1. Instantiate a PopupMenu with its constructor, which takes the current app Context and the View to
which the menu is anchored.

2. Use MenuInflater to inflate your menu resource into the Menu object returned
by PopupMenu.getMenu().

3. Call PopupMenu.show().
For example, here's a button that shows a popup menu:

<ImageButton
android:id="@+id/dropdown_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/descr_overflow_button"
android:src="@drawable/arrow_drop_down" />

The activity can then show the popup menu like this:

KotlinJava

findViewById<ImageButton>(R.id.dropdown_menu).setOnClickListener {
val popup = PopupMenu(this, it)
val inflater: MenuInflater = popup.menuInflater
inflater.inflate(R.menu.actions, popup.menu)
popup.show()
}

The menu is dismissed when the user selects an item or taps outside the menu area. You can
listen for the dismiss event using PopupMenu.OnDismissListener.

Handle click events

To perform an action when the user selects a menu item, implement


the PopupMenu.OnMenuItemClickListener interface and register it with your PopupMenu by
calling setOnMenuItemclickListener(). When the user selects an item, the system calls
the onMenuItemClick() callback in your interface.

This is shown in the following example:

KotlinJava

fun showMenu(v: View) {


PopupMenu(this, v).apply {
// MainActivity implements OnMenuItemClickListener.
setOnMenuItemClickListener(this@MainActivity)
inflate(R.menu.actions)
show()
}
}

override fun onMenuItemClick(item: MenuItem): Boolean {


return when (item.itemId) {
R.id.archive -> {
archive(item)
true
}
R.id.delete -> {
delete(item)
true
}
else -> false
}
}

Create a menu group


A menu group is a collection of menu items that share certain traits. With a group, you can do
the following:

• Show or hide all items using setGroupVisible().

• Enable or disable all items using setGroupEnabled().

• Specify whether all items are checkable using setGroupCheckable().

You can create a group by nesting <item> elements inside a <group> element in your menu
resource or by specifying a group ID with the add() method.

Here's an example of a menu resource that includes a group:

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


<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_save"
android:icon="@drawable/menu_save"
android:title="@string/menu_save" />
<!-- menu group -->
<group android:id="@+id/group_delete">
<item android:id="@+id/menu_archive"
android:title="@string/menu_archive" />
<item android:id="@+id/menu_delete"
android:title="@string/menu_delete" />
</group>
</menu>

The items that are in the group appear at the same level as the first item—all three items in the
menu are siblings. However, you can modify the traits of the two items in the group by
referencing the group ID and using the preceding methods. The system also never separates
grouped items. For example, if you declare android:showAsAction="ifRoom" for each item, they both
appear in the action bar or both appear in the action overflow.

Use checkable menu items

Figure 5. A submenu with checkable items.

A menu can be useful as an interface for turning options on and off, using a checkbox for
standalone options, or radio buttons for groups of mutually exclusive options. Figure 5 shows a
submenu with items that are checkable with radio buttons.

Note: Menu items in an options menu can't display a checkbox or radio button. If you make items in an options menu
checkable, manually indicate the checked state by swapping the icon or text, or both, each time the state changes.

You can define the checkable behavior for individual menu items using
the android:checkable attribute in the <item> element, or for an entire group with
the android:checkableBehavior attribute in the <group> element. For example, all items in this menu
group are checkable with a radio button:

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


<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item android:id="@+id/red"
android:title="@string/red" />
<item android:id="@+id/blue"
android:title="@string/blue" />
</group>
</menu>

The android:checkableBehavior attribute accepts one of the following:

single

Only one item from the group can be checked, resulting in radio buttons.

all

All items can be checked, resulting in checkboxes.

none

No items are checkable.

You can apply a default checked state to an item using the android:checked attribute in
the <item> element and change it in code with the setChecked() method.

When a checkable item is selected, the system calls your respective item-selected callback
method, such as onOptionsItemSelected(). This is where you set the state of the checkbox, because
a checkbox or radio button doesn't change its state automatically. You can query the current
state of the item—as it was before the user selected it—with isChecked() and then set the
checked state with setChecked(). This is shown in the following example:

KotlinJava

override fun onOptionsItemSelected(item: MenuItem): Boolean {


return when (item.itemId) {
R.id.vibrate, R.id.dont_vibrate -> {
item.isChecked = !item.isChecked
true
}
else -> super.onOptionsItemSelected(item)
}
}

If you don't set the checked state this way, then the visible state of the checkbox or radio
button doesn't change when the user selects it. When you do set the state, the activity
preserves the checked state of the item so that when the user opens the menu later, the
checked state that you set is visible.

Note: Checkable menu items are intended to be used only on a per-session basis and not saved after the app is
destroyed. If you have app settings that you want to save for the user, store the data using shared storage.

Add menu items based on an intent


Sometimes you want a menu item to launch an activity using an Intent, whether it's an activity in
your app or another app. When you know the intent you want to use and have a specific menu
item that initiates the intent, you can execute the intent with startActivity() during the
appropriate on-item-selected callback method, such as the onOptionsItemSelected() callback.

However, if you aren't certain that the user's device contains an app that handles the intent,
then adding a menu item that invokes it can result in a non-functioning menu item, because the
intent might not resolve to an activity. To solve this, Android lets you dynamically add menu
items to your menu when Android finds activities on the device that handle your intent.

To add menu items based on available activities that accept an intent, do the following:

1. Define an intent with the category CATEGORY_ALTERNATIVE or CATEGORY_SELECTED_ALTERNATIVE,


or both, plus any other requirements.

2. Call Menu.addIntentOptions(). Android then searches for any apps that can perform the intent and
adds them to your menu.

If there are no apps installed that satisfy the intent, then no menu items are added.

Note: CATEGORY_SELECTED_ALTERNATIVE is used to handle the selected element on the screen. Only use it when
creating a menu in onCreateContextMenu().

This is shown in the following example:

KotlinJava

override fun onCreateOptionsMenu(menu: Menu): Boolean {


super.onCreateOptionsMenu(menu)

// Create an Intent that describes the requirements to fulfill, to be


// included in the menu. The offering app must include a category value
// of Intent.CATEGORY_ALTERNATIVE.
val intent = Intent(null, dataUri).apply {
addCategory(Intent.CATEGORY_ALTERNATIVE)
}

// Search and populate the menu with acceptable offering apps.


menu.addIntentOptions(
R.id.intent_group, // Menu group to which new items are added.
0, // Unique item ID (none).
0, // Order for the items (none).
this.componentName, // The current activity name.
null, // Specific items to place first (none).
intent, // Intent created above that describes the requirements.
0, // Additional flags to control items (none).
null) // Array of MenuItems that correlate to specific items (none).

return true
}

For each activity found that provides an intent filter matching the intent defined, a menu item is
added, using the value in the intent filter's android:label as the menu item title and the app icon
as the menu item icon. The addIntentOptions() method returns the number of menu items added.

Note: When you call addIntentOptions(), it overrides all menu items by the menu group specified in the first
argument.

Let your activity be added to other menus


You can offer the services of your activity to other apps so your app can be included in the
menu of others—reversing the roles described earlier.

To be included in other app menus, define an intent filter as usual, but include
the CATEGORY_ALTERNATIVE or CATEGORY_SELECTED_ALTERNATIVE values, or both, for the intent
filter category. This is shown in the following example:

<intent-filter label="@string/resize_image">
...
<category android:name="android.intent.category.ALTERNATIVE" />
<category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
...
</intent-filter>

You might also like