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.
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.
O también, presentarlos como iconos (e incluso texto) si hay espacio disponible en la barra.
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:
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
.
main_menu.xml
abierto en el editor de menús2. 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:
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.
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.
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.
¿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()
}