Android Material Menus

Material Menus – Material Component For Android

A menu displays a list of choices on a temporary surface. They appear when users interact with a button, action, or other control.

Before getting into details. Check out my other post on material design,

Progress Indicators – Material Components For Android

Sliders – Material Component For Android

Material Menus – Material Component For Android

To work with material design, First, we need to add material design dependency.

    implementation 'com.google.android.material:material:1.3.0'Code language: JavaScript (javascript)

Types of menus

  1. Dropdown menus
  2. Exposed dropdown menus
Types of menus
Types of menus

Dropdown Menus

Dropdown menus display a list of options, triggered by an icon, button, or action. Their placement varies based on the element that opens them.

Based on the usage and design, dropdown menus are used in four different ways.

  1. Overflow menus
  2. Context menus
  3. Popup menus
  4. List popup window menus

Overflow menus

The menu appears after tapping these 3 dots located in the action bar.

Overflow Menus
Overflow menus

To create the overflow menu, First, create a menu XML file.

option_menu.xml:

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/option_1"
        android:title="Home" />
    <item android:id="@+id/option_2"
        android:title="Settings" />
    <item android:id="@+id/option_3"
        android:title="Logout" />
</menu>Code language: HTML, XML (xml)

Then, inflate the menu XML layout on onCreateOptionsMenu.

in your MainActivity.kt:

override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        val inflater: MenuInflater = menuInflater
        inflater.inflate(R.menu.option_menu, menu)
        return true
    }Code language: JavaScript (javascript)

Context menus

The context menu that appears when a TextView is long pressed.

context menus sample
Context menus

First, create Textview in your activity_main.xml layout,

<TextView
        android:id="@+id/textview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:text="@string/lorem_ipsum"
        android:padding="8dp"/>Code language: HTML, XML (xml)

In your code, inflate the context menu layout in onCreateContextMenu.

override fun onCreateContextMenu(menu: ContextMenu?, v: View?, menuInfo: ContextMenu.ContextMenuInfo?) {
        super.onCreateContextMenu(menu, v, menuInfo)
        val inflater: MenuInflater = menuInflater
        inflater.inflate(R.menu.option_menu, menu)
    }Code language: JavaScript (javascript)

Also, you can override the onContextItemSelected to handle the context menu item click.

override fun onContextItemSelected(item: MenuItem): Boolean {
        return when (item.itemId) {
            R.id.home -> {
                // Respond to context menu home click.
                Toast.makeText(this, "Home", Toast.LENGTH_SHORT).show()
                true
            }
            R.id.settings -> {
                // Respond to context menu settings click.
                true
            }
            R.id.logout -> {
                // Respond to context menu logout click.
                true
            }
            else -> super.onContextItemSelected(item)
        }
    }Code language: JavaScript (javascript)

Popup menus

The popup menu shows when a button is clicked.

Popup menu sample
Popup menus

Create a button in activity_main.xml,

<Button
        android:id="@+id/showMenu"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Show Popup Menu"
        android:visibility="visible"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>Code language: HTML, XML (xml)

With the click of a button, we need to create PopupMenu() and inflate the menu layout into the popup menu.

activityMainBinding.showMenu.setOnClickListener {
            val popup = PopupMenu(this, it)
            popup.menuInflater.inflate(R.menu.option_menu, popup.menu)
            popup.setOnMenuItemClickListener { menuItem: MenuItem ->
                // Respond to menu item click.
                return@setOnMenuItemClickListener true
            }
            popup.setOnDismissListener {
                // Respond to popup being dismissed.
            }
            // Show the popup menu.
            popup.show()
        }Code language: JavaScript (javascript)

Also, you can add a click listener for the popup menu by setting setOnMenuItemClickListener into the popup menu.

Adding icons on popup menus

Currently, there is no public API to add icons on popup menus. The following workaround is for API 21+, which uses library-only APIs, and is not guaranteed to work in future versions.

create a menu layout with icons,

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/home"
        android:icon="@drawable/ic_baseline_home_24"
        android:title="Home" />
    <item android:id="@+id/settings"
        android:icon="@drawable/ic_baseline_settings_24"
        android:title="Settings" />
    <item android:id="@+id/logout"
        android:icon="@drawable/ic_baseline_exit_to_app_24"
        android:title="Logout" />
</menu>Code language: HTML, XML (xml)

In code:

activityMainBinding.showMenu.setOnClickListener {
            val popup = PopupMenu(this, it)
            popup.menuInflater.inflate(R.menu.option_menu, popup.menu)
            if (popup.menu is MenuBuilder) {
                val menuBuilder = popup.menu as MenuBuilder
                menuBuilder.setOptionalIconsVisible(true)
                for (item in menuBuilder.visibleItems) {
                    val iconMarginPx =
                            TypedValue.applyDimension(
                                    TypedValue.COMPLEX_UNIT_DIP, ICON_MARGIN.toFloat(), resources.displayMetrics)
                                    .toInt()
                    if (item.icon != null) {
                        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
                            item.icon = InsetDrawable(item.icon, iconMarginPx, 0, iconMarginPx,0)
                        } else {
                            item.icon =
                                    object : InsetDrawable(item.icon, iconMarginPx, 0, iconMarginPx, 0) {
                                        override fun getIntrinsicWidth(): Int {
                                            return intrinsicHeight + iconMarginPx + iconMarginPx
                                        }
                                    }
                        }
                    }
                }
            }
            popup.show()
        }Code language: JavaScript (javascript)

List popup window menus

We can show the list of items in the popup menu using ListPopupWindow().

list of item in popup window
List Popup window menu

In code, First, create a listPopupWindow list of menu items.

val listPopupWindow = ListPopupWindow(this, null, R.attr.listPopupWindowStyle)
        // Set button as the list popup's anchor
        listPopupWindow.anchorView = activityMainBinding.showMenu
        // Set list popup's content
        val items = listOf("List Item 1", "List Item 2", "List Item 3")
        val adapter = ArrayAdapter(this, R.layout.list_item, items)
        listPopupWindow.setAdapter(adapter)
        // Set list popup's item click listener
        listPopupWindow.setOnItemClickListener { parent: AdapterView<*>?, view: View?, position: Int, id: Long ->
            // Respond to list popup window item click.
            // Dismiss popup.
            listPopupWindow.dismiss()
        }Code language: JavaScript (javascript)

Then, show the list popup menu by clicking the button.

activityMainBinding.showMenu.setOnClickListener {
            listPopupWindow.show()
        }

Exposed dropdown menus

Exposed dropdown menus display the currently selected menu item above the list of options. the exposed dropdown menus behavior same as a spinner. So, this will be the best alternative for spinners.

The exposed dropdown menu is implemented through the TextInputLayout.

Exposed dropdown menu with filedbox style
Exposed dropdown menus

In the layout:

<com.google.android.material.textfield.TextInputLayout
        android:id="@+id/textInputLayout"
        style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.ExposedDropdownMenu"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        android:hint="Select city">
        <AutoCompleteTextView
            android:id="@+id/menuAutocomplete"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            />
    </com.google.android.material.textfield.TextInputLayout>Code language: HTML, XML (xml)

in code, set the arrayAdapter into autoCompleteTextView.

val items = listOf("Chennai", "Delhi", "Mumbai", "Pune")
        val adapter = ArrayAdapter(this, R.layout.list_item, items)
        activityMainBinding.menuAutocomplete.setAdapter(adapter)Code language: JavaScript (javascript)

In the item layout (list_item.xml):

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:tools="http://schemas.android.com/tools"
    android:ellipsize="end"
    android:maxLines="1"
    android:padding="16dp"
    tools:text="List "
    android:textAppearance="?attr/textAppearanceSubtitle1" />Code language: HTML, XML (xml)

To have an outlined variation of the exposed dropdown menu, set the style to @style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu:

exposed dropdown menus with outlined box style
Outlined Exposed Dropdown menu

Non-editable variation
Disable the user input in the AutoCompleteTextView to have a non editable variation of the menu by setting android:inputType=”none” on the AutoCompleteTextView.

<AutoCompleteTextView
            android:id="@+id/menuAutocomplete"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="none"
            />Code language: HTML, XML (xml)

Setting a default value
In order to have a pre-selected value displayed, you can call setText(CharSequence text, boolean filter) on the AutoCompleteTextView with the filter set to false.

That’s it. Thank you for reading.


Posted

in

by

Tags:

Comments

2 responses to “Material Menus – Material Component For Android”

  1. Jakub Bober

    How to hide navigation bar when PopupMenu is showing?

  2. […] Material Menus – Material Component For Android […]

Leave a Reply

Your email address will not be published. Required fields are marked *