Recursos De Menú En Android

Los recursos de menú en Android te permiten expresar la estructura jerárquica de un menú en XML para separar su construcción del código fuente.

Aspecto de recursos de menú en Android
Menú de opciones en una App Bar

Las definiciones que provees en estos archivos se procesan con la clase MenuInflater, la cual inflar los elementos sobre la interfaz final. Esto es, convertir el archivo XML en un árbol de elementos Menu, MenuItem o SubMenu.

Ejemplo De Recursos De Menú En Android

En este tutorial verás cómo crear recursos de menú a partir de las etiquetas de construcción que provee el framework de Android, con el fin de prepararte el camino para crear distintos tipos de menús en tus aplicaciones.

La siguiente App es un ejemplo sencillo del manejo de recursos de menú:

Ejemplo de recursos de menú en Android

Puedes descargar el proyecto Android Studio con los recursos usados desde aquí:


Crear Recurso De Menu

Al igual que los demás tipos de recursos, los archivos de menú tienen características de ubicación y acceso particulares.

Carpeta De Menus

En primer lugar, debes ubicar crear un archivo de menú y ubicarlo en la carpeta res/menu/nombre_archivo.xml.

Desde Android Studio se resume a dar click derecho en tu carpeta res y luego seleccionar New > Android Resource File.

Crear recurso de menú en Android Studio

Al desplegarse la ventana de configuración, selecciona menu en el tipo de recursos y luego pon su nombre (main_menu en este ejemplo).

New Resource File con menu

Si confirmas, el nuevo archivo aparecerá en tu proyecto.

Carpeta res/menu en Android Studio

Acceder A Recurso De Menú

Con el archivo XML creado, puedes hacer referencia con su nombre como ID de recurso.

Desde código Kotlin o Java solo usa la navegación en la clase R de la forma:

R.menu.nombreMenu

Y desde XML usa el indicador @menu:

@menu/nombreMenu

Sintaxis De Recursos De Menu

Supongamos que deseamos crear un menú de opciones para la app bar de una actividad que representa el detalle de una factura:

Editor de menús en Android Studio

Abordar el diseño anterior requiere comprender la construcción de jerarquías de menús. Es decir, comprender que el recurso se produce usando una composición entre los siguientes nodos:

  • <menu>: Representa al menú concreto, actuando como padre de la jerarquía. Puede contener elementos <item> y <group>
  • <item>: Representa un ítem del menú. Puede contener un elemento <menú> para generar un submenú.
  • <group>: Representa un grupo de ítems. Es útil si deseas aplicar las mismas características a un conjunto de ítems.

Teniendo en cuenta los componentes anteriores, nuestro menú estaría compuesto de un elemento <menu> que contiene siete elementos <item>:

<?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/edit_action"
        android:icon="@drawable/ic_edit"
        android:title="@string/edit_action"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/delete_action"
        android:icon="@drawable/ic_delete"
        android:title="@string/delete_action"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/share_action"
        android:icon="@drawable/ic_share"
        android:title="@string/share_action"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/create_pdf_action"
        android:title="@string/create_pdf_action" />
    <item
        android:id="@+id/print_action"
        android:title="@string/print_action" />
    <item
        android:id="@+id/send_action"
        android:title="@string/send_action" />
    <item
        android:id="@+id/mark_as_paid_action"
        android:title="@string/mark_as_paid_action" />

</menu>

Desde la ventana Component Tree, en la pestaña Design, para el archivo main_menu.xml, verás el árbol resumido del código anterior:

Items De Menú

Claramente la definición expuesta en el ejemplo anterior será confusa sin comprender el contexto. Veamos la utilidad de los atributos principales de un ítem de menú.

ID De Ítem

Asigna el identificador al ítem de menú con android:id y permite referenciarle al momento de procesar sus acciones o personalizarlo en tiempo de ejecución.

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    if (item.itemId == R.id.edit_action) {
        Toast.makeText(this, "Edición", Toast.LENGTH_SHORT).show()
    }
    return true
}

En el código anterior consumimos el procesamiento del evento de click en un ítem de acción con onOptionsItemSelected() de la actividad.

Puedes ver que el argumento MenuItem nos permite acceder a su ID. Y es justo allí, donde comparamos el valor de android:id asignado previamente.

Título Del Item

El atributo android:title representa el titulo mostrado en pantalla del ítem cuando no se despliega como icono. Usa un recurso de string para aislar el literal y abrir las posibilidades de traducción:

android:title="@string/print_action"

Icono Del Item

Con el atributo android:icon puedes asignar un recurso drawable para mostrar un icono mostrado en pantalla. En el caso de la acción de edición le asignamos un vector llamado ic_edit:

android:icon="@drawable/ic_edit"
android:icon en item de menú

Normalmente usaremos los vectores de la miscelánea de Android que se crean con New > Vector Asset:

New Vector Asset en Android Studio

Presentación De La Acción

Con el atributo app:showAsAction puedes modificar la forma y momento en que aparece un ítem de menú en la App Bar.

Valor ifRoom

Si usas el valor ifRoom, el ítem se mostrará solo si hay espacio para proyectarlo.

Por ejemplo, ¿qué pasaría si marcamos tres ítems con ifRoom?:

<?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/share_action"
        android:title="@string/share_action"
        android:icon="@drawable/ic_share"
        android:orderInCategory="3"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/edit_action"
        android:icon="@drawable/ic_edit"
        android:orderInCategory="1"
        android:title="@string/edit_action"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/delete_action"
        android:icon="@drawable/ic_delete"
        android:orderInCategory="2"
        android:title="@string/delete_action"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/print_action"
        android:orderInCategory="4"
        android:title="@string/print_action" />
</menu>
Tres ítems con ifRoom, pero solo se muestran dos

En el caso de que hayan varios ítems con este valor, se priorizará aquellos que tengan el valor más preponderante en su atributo android:orderInCategory. Es por eso que "Compartir" se muestra en el menú overflow, ya que su prioridad es 3.

Sin embargo, si rotas la pantalla para añadir más espacio, share_action se adaptará y mostrará su icono:

share_action se muestra al existir el espacio suficiente

Valor withText

Con withText el ítem será mostrado como una acción e incluirá su título también. Debido a que este requerimiento requiere gran cantidad de espacio, su aparición será efectiva en orientaciones landscape o tabletas:

app:showAsAction="ifRoom|withText"
Ítem de editar con icono y título

Valor never

Usa el valor never si deseas que el ítem solo se muestre en el menú de overflow de la App Bar.

Valor always

Contrario a never, aplica always si es prioritario que el menú sea mostrado como acción. No obstante, si hay varios elementos marcados con este valor, puede que haya superposición.

Superposición con el título de la App Bar al usar always en todos los ítems

Valor collapseActionView

Otro valor sería collapseActionView que permite al action view asociado expandirse sobre la App Bar cuando se interactúa con él.

Expansión y contracción de SearchView sobre App Bar

El uso del SearchView es uno de los casos que aprovecha este valor para permitir la búsqueda en tu App:

<item
    android:id="@+id/app_bar_search"
    android:icon="@drawable/ic_search"
    android:title="@string/search_action"
    app:actionViewClass="androidx.appcompat.widget.SearchView"
    app:showAsAction="collapseActionView|ifRoom" />

Puedes ver más sobre la búsqueda en Android desde este tutorial (todo).

Personalizar Item De Menú

Los siguientes son atributos que te permiten modificar el view del ítem de menú.

Atributo app:actionLayout

El atributo app:actionLayout acepta un recurso de layout que será usado como el view de acción para el ítem especificado.

Switch como view de acción

Un uso común es la inclusión de un Switch al ítem de acción. Incluso el editor de menús en Android Studio lo provee como opción en la paleta:

Switch Item en Android Studio
Switch Item en Android Studio

Si lo añades, el IDE creará un layout automáticamente con un widget Switch en su interior:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <androidx.appcompat.widget.SwitchCompat
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:switchPadding="4dp"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true" />
</RelativeLayout>

Y luego lo asignara a app:actionLayout:

<item
    android:id="@+id/app_bar_switch"
    android:title="Switch"
    app:actionLayout="@layout/switch_item"
    app:showAsAction="always" />

Atributo app:actionViewClass

Acepta el nombre de una clase que sea heredera de View, para ser usada como el view de acción. Vimos un ejemplo de su uso con SearchView anteriormente.

Atributo app:actionProviderClass

El atributo app:actionProviderClass usa un ejemplar de ActionProvider para ser usado como ítem de acción. Por ejemplo el ShareActionProvider (todo).

Item De Menú Con CheckBox

Si deseas mostrar un control CheckBox en el ítem de menú, entonces usa el atributo android:checkable en true:

Item de menú con android:checkable

A su vez puedes acompañarlo de android:checked con true para determinar si es marcado por defecto:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:checkable="true"
        android:checked="true"
        android:title="Mostrar consumo" />
</menu>

Desactivar Y Ocultar Ítem De Menú

Los ítems de menú pueden ser desactivado (no reciben acciones pero se muestran) con el atributo android:enabled en false.

U ocultados (ya no son renderizados) con android:visible en false.

Comportamiento De Marcado En Grupo

Modifica el comportamiento de marcado de un grupo de ítems a través del atributo android:checkingBehavior.

Asignar none no permitirá que ningún ítem sea marcable. Por otro lado, usar all despliega Checkboxes en todos los ítems del grupo para permitir que todos sean marcados:

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

    <group android:checkableBehavior="all">
        <item android:title="Mostrar desplazamiento" />
        <item android:title="Mostrar velocidad" />
        <item android:title="Mostrar aceleración" />
    </group>
</menu>
Atributo android:checkableBehavior con all

Y asignar single especifica que solo un ítem del grupo pueda ser marcado, por lo que aparecerán RadioButtons en los elementos del grupo:

Atributo android:checkableBehavior con single

Esta constante es de gran utilidad cuando usamos el Navigation Drawer y deseamos sostener la selección de una sola pantalla.

Submenús

Los componentes <menu> también pueden actuar como elemento de composición en la jerarquía para construir submenús:

Submenú en Android

Crear esta estructura requiere añadir una etiqueta <menu> dentro de una <item> para tratarlo de a igual en la jerarquía:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:title="Sección">
        <menu>
            <item android:title="Opción 1" />
            <item android:title="Opción 2" />
            <item android:title="Opción 3" />
            <item android:title="Opción 4" />
        </menu>
    </item>
</menu>

Normalmente los submenús no son un patrón cómodo en los menús desplegables. Sin embargo, son de gran utilidad en la creación del Navigation Views con separación de secciones.

Inflar Un Recurso De Menú

Como ya se había dicho, debes usas al componente MenuInflater para convertir el archivo XML a objetos en tiempo de ejecución.

Lograr esto requiere la invocación del método inflate() el cual recibe el ID del menú y la instancia del objeto Menu que recibirá el resultado.

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

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

Para los Options Menus, la creación se da en el método onCreateOptionsMenu() de la actividad o en la versión del equivalente del fragmento.

Tipos De Menús

En el ejemplo anterior, inflamos un menú de opciones de una actividad. Sin embargo existen otros tipos de menú:

Cada escenario usa un momento específico para el inflado y puede tomar diferentes usos de los parámetros vistos en este tutorial. Haz click en cada elemento para dirigirte al tutorial que explica a fondo como crear y procesar eventos para cada tipo de menú.

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!