Options Menu En Android

El options menu en Android representa el menú de acciones globales que se integra en la App Bar de tus actividades. Su propósito es brindarle al usuario acciones que son relevantes al contexto de la actividad o fragmento actual.

Aspecto de Options Menu en Android

Como viste en el tutorial de recursos de menú, la App Bar alberga los ítems del menú de opciones. Donde se agrega por defecto a todos los ítems al menú desplegable que se visualiza al presionar el icono de tres puntos.

Items en action overflow

O también, presentarlos como iconos (e incluso texto) si hay espacio disponible en la barra.

Action ítem con icono

Ejemplo De Options Menu En Android

En este tutorial aprenderás a crear un options menu, procesar los eventos de click en los ítems y a modificar en tiempo de ejecución al menú. Para ello verás como guía la siguiente App de ejemplo:

App ejemplo de Options Menu en Android

Puedes descargar el proyecto Android Studio desde el siguiente enlace:

Teniendo esto claro, comencemos con el primer paso de la receta para construir un menu de opciones.

1. Crear Recurso De Menú

Nuestro ejemplo muestra cuatro ítems asociados a una actividad que presenta: búsqueda, creación de categorías, creación de etiquetas y ajustes. El siguiente árbol resume al menú:

Recordemos que la estructura de los menús la establecemos a través de una definición XML. Dicho recurso de menú debe ser guardado en la carpeta res/menu y contener un nodo padre <menu>.

El siguiente archivo de menú nombrado main_menu.xml, representa el diseño que deseamos:

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

    <item
        android:id="@+id/search"
        android:icon="@drawable/ic_search"
        android:title="@string/search"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/add_category"
        android:title="@string/add_category" />
    <item
        android:id="@+id/add_label"
        android:title="@string/add_label" />
    <item
        android:id="@+id/settings"
        android:title="@string/settings" />
</menu>

Recuerda que app:showAsAction permite mostrar un ítem como acción en la barra si usamos ifRoom. En este caso, el icono de la búsqueda con ID search.

Archivo main_menu.xml abierto en el editor de menús

2. Inflar Options Menu

El menú de opciones es añadido al inicio del ciclo de vida de las actividades (aunque los fragmentos también pueden contribuir en su creación). El momento adecuado de combinarlo está determinado por el método de enganche onCreateOptionsMenu().

Este método te provee la instancia Menu que será integrado a la App Bar. Para añadirlo puedes usar el atajo de sobrescritura de métodos presionando Ctrl+O en Android Studio:

Override Members en Android Studio (Ctrl+O)

Tu responsabilidad es usar a MenuInflater.inflate() para inflar tu recurso de menú sobre el objeto:

override fun onCreateOptionsMenu(menu: Menu?): Boolean {
    menuInflater.inflate(R.menu.main_menu, menu)
    return true
}

En el código anterior referenciamos al recurso de menú con R.menu.main_menu junto al parámetro menu. Retornamos true para indicar que consumiremos el recurso.

3. Procesar Eventos De Click

Cuando la observación interna de los clicks sobre los ítems de acción detecta un evento, el sistema ejecuta al método onOptionsItemSelected() de tu actividad o fragmento.

Su parámetro es la instancia MenuItem que ha recibido el estímulo, por lo que tendrás acceso a su propiedad itemId para realizar comparaciones y determinar acciones:

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.search, R.id.add_category, R.id.add_label -> {
            showOption(item.title)
            true
        }
        R.id.settings -> {
            goToSettings()
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

private fun showOption(title: CharSequence) {
    Toast.makeText(this, title, Toast.LENGTH_SHORT).show()
}

private fun goToSettings() {
    val intent = Intent(this, SettingsActivity::class.java)
    startActivity(intent)
}

En el código anterior, usamos una expresión when para retornar el resultado de onOptionsItemSelected(). Si el resultado es true, se consume el evento desde tu lógica, de lo contrario se delega al padre con super.

La primera rama del when maneja a los tres primeros identificadores de los ítems del menú (search, add_category y add_label). Cuando la propiedad MenuItem.itemId del argumento coincide con estas opciones, desplegamos un Toast para mostrar el título del item.

Y en el caso de R.id.settings, iniciamos una actividad de ajustes que hemos creado desde la plantilla New>Activity>Settings Activity.

Iniciar actividad de ajustes desde Options Menu

Atributo android:onClick

También es posible usar al atributo android:onClick de los componentes <item> para especificar el método de acción que será ejecutado al realizar click:

fun createCategory(item:MenuItem){
    Log.d("android:onClick", "createCategory()")
}

Ten en cuenta que para procesar este enlace, el método debe tener un único parámetro del tipo MenuItem para representar al elemento clickeado. Además debe estar declarado en una Activity.

Si vas a tu recurso de menú y añades el atributo android:onClick, Android Studio te mostrará a createCategory() como un candidato a elegir.

Atributo android:onClick en ítem de menú

Asignando este método se logueará en la ventana Logcat cada click en R.id.add_category.

<item
    android:id="@+id/add_category"
    android:onClick="createCategory"
    android:title="@string/add_category" />

4. Modificar Menú Programáticamente

Supongamos que deseamos remover el ítem de búsqueda luego de presionar el botón que tenemos en el layout principal.

Modificar programáticamente Options Menu en Android

¿Cómo hacerlo?

Lo primero que se nos viene la mente es modificar el menú desde onCreateOptionsMenu(). Sin embargo, este método es llamado una vez para crear el estado inicial del objeto Menu incrustado en la app bar. Por lo que solo podrías realizar una modificación inicial.

override fun onCreateOptionsMenu(menu: Menu?): Boolean {
    menuInflater.inflate(R.menu.main_menu, menu)
    menu?.add("Ayuda")
    return true
}

Para cambiar la estructura del menú a lo largo del ciclo de vida debes usar a onPrepareOptionsMenu(). Este recibe el objeto Menu que está inflado actualmente, por lo que es posible realizar el cambio de visibilidad:

override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
    val findItem = menu?.findItem(R.id.search)
    findItem?.isVisible = visibleSearch
    return true
}

En este caso usamos a Menu.findItem() para encontrar un ítem por su ID. Luego asignamos la centinela booleana visibleSearch para controlar el estado de visibilidad del ítem del menú con la propiedad isVisible.

Ahora bien, onPrepareOptionsMenu() se invoca cuando:

  • La actividad se inicia
  • Al mostrarse el action overflow
  • Cuando invocas a invalidateOptionsMenu() en el momento que ocurra el evento que desencadene la modificación

Debido a que deseamos ejecutarlo al clickear el botón, entonces asignamos una escucha con setOnClickListener() para llamar a invalidateOptionsMenu() y cambiar la visibilidad.

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

    findViewById<Button>(R.id.send_button).setOnClickListener {
        visibleSearch = false
        invalidateOptionsMenu()
    }
}

El método invalidateOptionsMenu() le dice a la actividad que nuestro menú ya no es válido, por lo que necesitamos preparar un repintado que lo haga consistente en onPrepareOptionsMenu().

En caso de que quisieras reponer la visibilidad, entonces actualiza la bandera y llama de nuevo a invalideOptionsMenu(). Por ejemplo:

override fun onStop() {
    super.onStop()
    visibleSearch = true
    invalidateOptionsMenu()
}

Más Contenidos Android

Únete Al Discord De Develou

Si tienes problemas con el código de este tutorial, preguntas, recomendaciones o solo deseas discutir sobre desarrollo Android conmigo y otros desarrolladores, únete a la comunidad de Discord de Develou y siéntete libre de participar como gustes. ¡Te espero!