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.
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ú:
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.
Al desplegarse la ventana de configuración, selecciona menu en el tipo de recursos y luego pon su nombre (main_menu
en este ejemplo).
Si confirmas, el nuevo archivo aparecerá en tu proyecto.
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:
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"
Normalmente usaremos los vectores de la miscelánea de Android que se crean con New > Vector Asset:
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>
ifRoom
, pero solo se muestran dosEn 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 suficienteValor 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"
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.
always
en todos los ítemsValor collapseActionView
Otro valor sería collapseActionView
que permite al action view asociado expandirse sobre la App Bar cuando se interactúa con él.
SearchView
sobre App BarEl 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ónUn 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:
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
:
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>
Y asignar single
especifica que solo un ítem del grupo pueda ser marcado, por lo que aparecerán RadioButtons en los elementos del grupo:
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:
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ú.