Agregar menús

Prueba la forma de Compose
Jetpack Compose es el kit de herramientas de IU recomendado para Android. Obtén información para agregar componentes en Compose.

Los menús son un componente común de la interfaz de usuario en muchos tipos de apps. Para proporcionar una experiencia de usuario conocida y uniforme, usa las APIs de Menu para presentar al usuario acciones y otras opciones en las actividades.

Una imagen que muestra un ejemplo de menú ampliado
Figura 1. Un menú activado por un toque en el ícono, que aparece debajo del ícono del menú ampliado.

En este documento, se muestra cómo crear tres tipos fundamentales de presentaciones de menús o acciones en todas las versiones de Android:

Menú de opciones y barra de la app
El menú de opciones es la colección principal de elementos de menú de una actividad. Es donde debes colocar las acciones que tienen un impacto global en la app, como "Buscar", "Redactar correo electrónico" y "Configuración".

Consulta la sección Cómo crear un menú de opciones.

Menú contextual y modo de acción contextual
Un menú contextual es un menú flotante que aparece cuando el usuario mantiene presionado un elemento. Proporciona acciones que afectan el contenido seleccionado o el marco contextual.

En el modo de acción contextual, se muestran los elementos de acción que afectan al contenido seleccionado en una barra en la parte superior de la pantalla y se permite al usuario seleccionar varios elementos.

Consulta la sección Cómo crear un menú contextual.

Menú emergente
Un menú emergente muestra una lista vertical de elementos que está anclada a la vista que invoca el menú. Es adecuado para proporcionar una ampliación de acciones relacionadas con contenido específico o para proporcionar opciones en una segunda parte de un comando. Las acciones de un menú emergente no afectan directamente al contenido correspondiente, ya que para eso están las acciones contextuales. En cambio, el menú emergente es para acciones extendidas relacionadas con partes del contenido de la actividad.

Consulta la sección Cómo crear un menú emergente.

Cómo definir un menú en XML

Para todos los tipos de menús, Android proporciona un formato XML estándar que permite definir los elementos de menú. En lugar de incorporar un menú en el código de la actividad, define un menú y todos los elementos en un recurso de menú XML. Luego, puedes aumentar el recurso de menú (cargarlo como un objeto Menu) en la actividad o el fragmento.

El uso de un recurso de menú es una práctica recomendada por los siguientes motivos:

  • Es más fácil visualizar la estructura del menú en XML.
  • Separa el contenido del menú del código de comportamiento de la app.
  • Te permite crear configuraciones alternativas del menú para diferentes versiones de plataforma, tamaños de pantalla y otras configuraciones aprovechando el framework de recursos de la app.

Para definir un menú, crea un archivo en formato XML dentro del directorio res/menu/ del proyecto y compila el menú con los siguientes elementos:

<menu>
Define un Menu, que es un contenedor para elementos de menú. Un elemento <menu> debe ser el nodo raíz del archivo y puede contener uno o más elementos <item> y <group>.
<item>
Crea un MenuItem, que representa un solo elemento en un menú. Este elemento puede contener un elemento <menu> anidado para crear un submenú.
<group>
Es un contenedor opcional e invisible para elementos <item>. Te permite categorizar los elementos de menú para que compartan propiedades, como el estado de la actividad y la visibilidad. Para obtener más información, consulta la sección Cómo crear un grupo de menú.

Aquí presentamos un menú de ejemplo denominado game_menu.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/new_game"
          android:icon="@drawable/ic_new_game"
          android:title="@string/new_game"
          app:showAsAction="ifRoom"/>
    <item android:id="@+id/help"
          android:icon="@drawable/ic_help"
          android:title="@string/help" />
</menu>

El elemento <item> admite varios atributos que puedes usar para definir la apariencia y el comportamiento de un elemento. Los elementos del menú anterior incluyen los siguientes atributos:

android:id
Es el ID de un recurso que es exclusivo del elemento y permite que la app lo reconozca cuando el usuario lo selecciona.
android:icon
Es la referencia a un elemento de diseño para usar como el ícono del elemento.
android:title
Es la referencia a una string para usar como el título del elemento.
android:showAsAction
La especificación de cuándo y cómo este elemento aparece como un elemento de acción en la barra de la app.

Estos son los atributos más importantes que usas, pero hay muchos más disponibles. Para obtener información sobre todos los atributos admitidos, consulta la documentación del recurso de menú.

Puedes agregar un submenú a un elemento en cualquier menú agregando un elemento <menu> como elemento secundario de un <item>. Los submenús son útiles cuando la app tiene muchas funciones que se pueden organizar en temas, como elementos de la barra de menús de una app para PC, como File, Edit y View. Observa el siguiente ejemplo:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/file"
          android:title="@string/file" >
        <!-- "file" submenu -->
        <menu>
            <item android:id="@+id/create_new"
                  android:title="@string/create_new" />
            <item android:id="@+id/open"
                  android:title="@string/open" />
        </menu>
    </item>
</menu>

Para usar el menú en tu actividad, _aumenta_ el recurso de menú y convierte el recurso XML en un objeto programable con MenuInflater.inflate(). En las siguientes secciones, se muestra cómo aumentar un menú para cada tipo de menú.

Cómo crear un menú de opciones

El menú de opciones, como el que se muestra en la figura 1, es el lugar en el que debes incluir acciones y otras opciones que son relevantes para el contexto de la actividad actual, como "Buscar", "Redactar correo electrónico" y "Configuración".

Una imagen que muestra la barra de la app de Hojas de cálculo de Google
Figura 2: App de Hojas de cálculo de Google que muestra varios botones, incluido el botón del menú ampliado de acciones

Puedes declarar elementos para el menú de opciones desde tu subclase Activity o una subclase Fragment. Si tanto la actividad como los fragmentos declaran elementos para el menú de opciones, se los combina en la IU. Los elementos de la actividad aparecen primero, y después aparecen los elementos de cada fragmento, en el orden en que los fragmentos se agregan a la actividad. Si es necesario, puedes reordenar los elementos de menú con el atributo android:orderInCategory en cada <item> que necesites mover.

Para especificar el menú de opciones de una actividad, anula onCreateOptionsMenu(). Los fragmentos proporcionan su propia devolución de llamada onCreateOptionsMenu(). En este método, puedes aumentar el recurso de menú, definido en XML, hacia el Menu proporcionado en la devolución de llamada. Esto se muestra en el siguiente ejemplo:

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    val inflater: MenuInflater = menuInflater
    inflater.inflate(R.menu.game_menu, menu)
    return true
}

Java

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.game_menu, menu);
    return true;
}

También puedes agregar elementos de menú con add() y recuperar elementos con findItem() para revisar sus propiedades con las APIs de MenuItem.

Cómo controlar eventos de clic

Cuando el usuario selecciona un elemento del menú de opciones, incluidos los elementos de acción de la barra de la app, el sistema llama al método onOptionsItemSelected() de la actividad. Este método pasa el MenuItem seleccionado. Puedes identificar el elemento si llamas a getItemId(), que muestra el ID único del elemento de menú, definido por el atributo android:id en el recurso de menú o con un valor entero proporcionado al método add(). Puedes hacer coincidir este ID con elementos de menú conocidos para realizar la acción correspondiente.

Kotlin

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    // Handle item selection.
    return when (item.itemId) {
        R.id.new_game -> {
            newGame()
            true
        }
        R.id.help -> {
            showHelp()
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

Java

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection.
    switch (item.getItemId()) {
        case R.id.new_game:
            newGame();
            return true;
        case R.id.help:
            showHelp();
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

Cuando controles correctamente un elemento de menú, muestra true. Si no controlas el elemento de menú, llama a la implementación de la superclase de onOptionsItemSelected(). La implementación predeterminada muestra un valor falso.

Si la actividad incluye fragmentos, el sistema llama primero a onOptionsItemSelected() para la actividad y, a continuación, lo hace para cada fragmento en el orden en que se agregaron, hasta que uno muestre true o se llamen todos los fragmentos.

Cómo cambiar los elementos del menú durante el tiempo de ejecución

Después de que el sistema llama a onCreateOptionsMenu(), retiene una instancia del Menu que tú completas y no llama a onCreateOptionsMenu() nuevamente, a menos que se invalide el menú. Sin embargo, usa onCreateOptionsMenu() solo para crear el estado inicial del menú, y no para hacer cambios durante el ciclo de vida de la actividad.

Si deseas modificar el menú de opciones a partir de eventos que tengan lugar durante el ciclo de vida de la actividad, puedes hacerlo en el método onPrepareOptionsMenu(). Este método te pasa el objeto Menu como existe en ese momento para que puedas modificarlo, por ejemplo, agregando, quitando o inhabilitando elementos. Los fragmentos también proporcionan una devolución de llamada de onPrepareOptionsMenu().

Se considera que el menú de opciones está siempre abierto cuando los elementos de menú se presentan en la barra de la app. Cuando se produce un evento y deseas realizar una actualización del menú, llama a invalidateOptionsMenu() para solicitar que el sistema llame a onPrepareOptionsMenu().

Cómo crear un menú contextual

Una imagen que muestra un menú contextual flotante
Figura 3: Un menú contextual flotante.

Un menú contextual ofrece acciones que afectan a un elemento o un marco contextual específicos en la IU. Puedes proporcionar un menú contextual para cualquier vista, aunque se usan con mayor frecuencia para elementos en RecylerView o en otras colecciones de vistas en las que el usuario puede realizar acciones directamente en cada elemento.

Existen dos maneras de proporcionar acciones contextuales:

  • En un menú contextual flotante. Un menú aparece como una lista flotante de elementos de menú, similar a un cuadro de diálogo, cuando el usuario mantiene presionado un elemento de una vista que declara admitir un menú contextual. Los usuarios pueden realizar una acción contextual en un elemento por vez.
  • En el modo de acción contextual. Este modo es una implementación del sistema de ActionMode que muestra una barra de acciones contextuales(CAB) en la parte superior de la pantalla con elementos de acción que afectan a los elementos seleccionados. Cuando este modo está activo, los usuarios pueden realizar una acción en varios elementos a la vez, si la app lo admite.

Nota: El menú contextual no admite accesos directos ni íconos de elementos.

Cómo crear un menú contextual flotante

Para proporcionar un menú contextual flotante, haz lo siguiente:

  1. Para registrar el View con el que está asociado el menú contextual, llama a registerForContextMenu() y pásale el View.

    Si la actividad usa una RecyclerView y deseas que cada elemento proporcione el mismo menú contextual, registra todos los elementos de un menú contextual pasando la RecyclerView a registerForContextMenu().

  2. Implementa el método onCreateContextMenu() en tu Activity o Fragment.

    Cuando la vista registrada recibe un evento de mantener presionado, el sistema llama a tu método onCreateContextMenu(). Aquí es donde defines los elementos del menú, por lo general, agrandando un recurso de menú, como en el siguiente ejemplo:

    Kotlin

        override fun onCreateContextMenu(menu: ContextMenu, v: View,
                                menuInfo: ContextMenu.ContextMenuInfo) {
            super.onCreateContextMenu(menu, v, menuInfo)
            val inflater: MenuInflater = menuInflater
            inflater.inflate(R.menu.context_menu, menu)
        }
        

    Java

        @Override
        public void onCreateContextMenu(ContextMenu menu, View v,
                                        ContextMenuInfo menuInfo) {
            super.onCreateContextMenu(menu, v, menuInfo);
            MenuInflater inflater = getMenuInflater();
            inflater.inflate(R.menu.context_menu, menu);
        }
        

    MenuInflater te permite aumentar el menú contextual desde un recurso de menú. Los parámetros del método de devolución de llamada incluyen la View que el usuario selecciona y un objeto ContextMenu.ContextMenuInfo que proporciona información adicional sobre el elemento seleccionado. Si tu actividad tiene varias vistas, cada una de las cuales proporciona un menú contextual diferente, puedes usar estos parámetros para determinar qué menú contextual debes aumentar.

  3. Implementa onContextItemSelected(), como se muestra en el siguiente ejemplo. Cuando el usuario selecciona un elemento de menú, el sistema llama a este método para que puedas realizar la acción apropiada.

    Kotlin

        override fun onContextItemSelected(item: MenuItem): Boolean {
            val info = item.menuInfo as AdapterView.AdapterContextMenuInfo
            return when (item.itemId) {
                R.id.edit -> {
                    editNote(info.id)
                    true
                }
                R.id.delete -> {
                    deleteNote(info.id)
                    true
                }
                else -> super.onContextItemSelected(item)
            }
        }
        

    Java

        @Override
        public boolean onContextItemSelected(MenuItem item) {
            AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
            switch (item.getItemId()) {
                case R.id.edit:
                    editNote(info.id);
                    return true;
                case R.id.delete:
                    deleteNote(info.id);
                    return true;
                default:
                    return super.onContextItemSelected(item);
            }
        }
        

    El método getItemId() consulta el ID del elemento de menú seleccionado, que debes asignar a cada elemento de menú en XML con el atributo android:id, como se muestra en Cómo definir un menú en XML.

    Cuando controles correctamente un elemento de menú, muestra true. Si no controlas el elemento de menú, pásalo a la implementación de la superclase. Si la actividad incluye fragmentos, esta recibe la devolución de llamada primero. Cuando llamas a una superclase cuando esta no está controlada, el sistema pasa el evento al método de devolución de llamada correspondiente en cada fragmento, uno por vez, en el orden en el que se agregó cada fragmento, hasta que se muestra true o false. Las implementaciones predeterminadas para Activity y android.app.Fragment muestran false, por lo que siempre debes llamar a la superclase cuando esta no está controlada.

Cómo usar el modo de acción contextual

El modo de acción contextual es una implementación del sistema de ActionMode que centra la interacción del usuario en la realización de acciones contextuales. Cuando un usuario habilita este modo seleccionando un elemento, aparece una barra de acciones contextuales en la parte superior de la pantalla para presentar las acciones que el usuario puede realizar en los elementos seleccionados. Cuando este modo está habilitado, el usuario puede seleccionar varios elementos, si tu app lo admite, y anular la selección de elementos y seguir navegando dentro de la actividad. El modo de acción se inhabilita y la barra de acciones contextuales desaparece cuando el usuario anula la selección de todos los elementos, presiona el botón Atrás o presiona la acción Listo en el lado izquierdo de la barra.

En las vistas que proporcionan acciones contextuales, por lo general, debes invocar el modo de acción contextual cuando se produce uno de estos dos eventos (o ambos):

  • El usuario mantiene presionada la vista.
  • El usuario selecciona una casilla de verificación o un componente similar de la IU en la vista.

La forma en que la app invoca el modo de acción contextual y define el comportamiento de cada acción depende de tu diseño. Existen dos diseños:

  • Para acciones contextuales en vistas individuales arbitrarias
  • Para acciones contextuales por lotes de grupos de elementos en una RecyclerView, lo que permite al usuario seleccionar varios elementos y realizar una acción en todos ellos

En las siguientes secciones, se describe la configuración necesaria para el primer escenario.

Cómo habilitar el modo de acción contextual para vistas individuales

Si deseas invocar el modo de acción contextual solo cuando el usuario selecciona vistas específicas, haz lo siguiente:

  1. Implementa la interfaz ActionMode.Callback como se muestra en el siguiente ejemplo. En sus métodos de devolución de llamada, puedes especificar las acciones de la barra de acciones contextuales, responder a eventos de clic en elementos de acción y controlar otros eventos de ciclo de vida del modo de acción.

    Kotlin

        private val actionModeCallback = object : ActionMode.Callback {
            // Called when the action mode is created. startActionMode() is called.
            override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
                // Inflate a menu resource providing context menu items.
                val inflater: MenuInflater = mode.menuInflater
                inflater.inflate(R.menu.context_menu, menu)
                return true
            }
    
            // Called each time the action mode is shown. Always called after
            // onCreateActionMode, and might be called multiple times if the mode
            // is invalidated.
            override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
                return false // Return false if nothing is done
            }
    
            // Called when the user selects a contextual menu item.
            override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
                return when (item.itemId) {
                    R.id.menu_share -> {
                        shareCurrentItem()
                        mode.finish() // Action picked, so close the CAB.
                        true
                    }
                    else -> false
                }
            }
    
            // Called when the user exits the action mode.
            override fun onDestroyActionMode(mode: ActionMode) {
                actionMode = null
            }
        }
        

    Java

        private ActionMode.Callback actionModeCallback = new ActionMode.Callback() {
    
            // Called when the action mode is created. startActionMode() is called.
            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                // Inflate a menu resource providing context menu items.
                MenuInflater inflater = mode.getMenuInflater();
                inflater.inflate(R.menu.context_menu, menu);
                return true;
            }
    
            // Called each time the action mode is shown. Always called after
            // onCreateActionMode, and might be called multiple times if the mode
            // is invalidated.
            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                return false; // Return false if nothing is done.
            }
    
            // Called when the user selects a contextual menu item.
            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
               switch (item.getItemId()) {
                    case R.id.menu_share:
                        shareCurrentItem();
                        mode.finish(); // Action picked, so close the CAB.
                        return true;
                    default:
                        return false;
                }
            }
    
            // Called when the user exits the action mode.
            @Override
            public void onDestroyActionMode(ActionMode mode) {
                actionMode = null;
            }
        };
        

    Estas devoluciones de llamada de evento son casi exactamente las mismas que las del menú de opciones, excepto que cada una de ellas también pasa el objeto ActionMode asociado al evento. Puedes usar las APIs de ActionMode para realizar varios cambios en la CAB, como revisar el título y el subtítulo con setTitle() y setSubtitle(), lo que resulta útil para indicar cuántos elementos se seleccionaron.

    En el ejemplo anterior, se establece la variable actionMode en null cuando se destruye el modo de acción. En el siguiente paso, verás cómo se inicializa y cómo guardar la variable de miembro en la actividad o el fragmento puede ser útil.

  2. Llama a startActionMode() cuando desees mostrar la barra, como cuando el usuario mantiene presionada la vista.

    Kotlin

        someView.setOnLongClickListener { view ->
            // Called when the user performs a touch & hold on someView.
            when (actionMode) {
                null -> {
                    // Start the CAB using the ActionMode.Callback defined earlier.
                    actionMode = activity?.startActionMode(actionModeCallback)
                    view.isSelected = true
                    true
                }
                else -> false
            }
        }
        

    Java

        someView.setOnLongClickListener(new View.OnLongClickListener() {
            // Called when the user performs a touch & hold on someView.
            public boolean onLongClick(View view) {
                if (actionMode != null) {
                    return false;
                }
    
                // Start the CAB using the ActionMode.Callback defined earlier.
                actionMode = getActivity().startActionMode(actionModeCallback);
                view.setSelected(true);
                return true;
            }
        });
        

    Cuando llamas a startActionMode(), el sistema muestra el ActionMode creado. Si guardas esto en una variable de miembro, podrás realizar cambios en la barra de acciones contextuales en respuesta a otros eventos. En el ejemplo anterior, se usa el ActionMode para garantizar que la instancia del ActionMode no se vuelva a crear si ya está activa, controlando si el miembro tiene valor nulo antes de iniciar el modo de acción.

Cómo crear un menú emergente

Una imagen en la que se muestra un menú contextual en la app de Gmail anclado al botón del menú ampliado en la parte superior derecha.
Figura 4: Un menú contextual en la app de Gmail anclado al botón del menú ampliado en la esquina superior derecha

Un PopupMenu es un menú modal anclado a una View. Aparece debajo de la vista anclada si hay espacio o, de lo contrario, sobre esta. Es útil para lo siguiente:

  • Proporcionar un menú de estilo ampliado para las acciones que se relacionan con contenido específico, como los encabezados de correo electrónico de Gmail, que se muestran en la figura 4.
  • Proporcionar la segunda parte de una oración de comandos, como un botón marcado Agregar que produce un menú emergente con diferentes opciones Agregar.
  • Proporcionar un menú similar a un Spinner que no retiene una selección persistente.

Si defines el menú en XML, puedes hacer esto para mostrar el menú emergente:

  1. Crea una instancia de PopupMenu con su constructor, que toma el Context de la app actual y la View a la que se ancla el menú.
  2. Usa MenuInflater para aumentar el recurso de menú hacia el objeto Menu que muestra PopupMenu.getMenu().
  3. Llamar a PopupMenu.show()

Por ejemplo, aquí se muestra un botón que muestra un menú emergente:

<ImageButton
    android:id="@+id/dropdown_menu"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:contentDescription="@string/descr_overflow_button"
    android:src="@drawable/arrow_drop_down" />

La actividad puede mostrar el menú emergente de la siguiente manera:

Kotlin

findViewById<ImageButton>(R.id.dropdown_menu).setOnClickListener {
    val popup = PopupMenu(this, it)
    val inflater: MenuInflater = popup.menuInflater
    inflater.inflate(R.menu.actions, popup.menu)
    popup.show()
}

Java

findViewById(R.id.dropdown_menu).setOnClickListener(v -> {
    PopupMenu popup = new PopupMenu(this, v);
    popup.getMenuInflater().inflate(R.menu.actions, popup.getMenu());
    popup.show();
});

El menú se descarta cuando el usuario selecciona un elemento o toca fuera del área del menú. Puedes escuchar el evento de descarte con PopupMenu.OnDismissListener.

Cómo controlar eventos de clic

Para realizar una acción cuando el usuario selecciona un elemento de menú, implementa la interfaz de PopupMenu.OnMenuItemClickListener y regístrala en el PopupMenu llamando a setOnMenuItemclickListener(). Cuando el usuario selecciona un elemento, el sistema llama a la devolución de llamada onMenuItemClick() en la interfaz.

Esto se muestra en el siguiente ejemplo:

Kotlin

fun showMenu(v: View) {
    PopupMenu(this, v).apply {
        // MainActivity implements OnMenuItemClickListener.
        setOnMenuItemClickListener(this@MainActivity)
        inflate(R.menu.actions)
        show()
    }
}

override fun onMenuItemClick(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.archive -> {
            archive(item)
            true
        }
        R.id.delete -> {
            delete(item)
            true
        }
        else -> false
    }
}

Java

public void showMenu(View v) {
    PopupMenu popup = new PopupMenu(this, v);

    // This activity implements OnMenuItemClickListener.
    popup.setOnMenuItemClickListener(this);
    popup.inflate(R.menu.actions);
    popup.show();
}

@Override
public boolean onMenuItemClick(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.archive:
            archive(item);
            return true;
        case R.id.delete:
            delete(item);
            return true;
        default:
            return false;
    }
}

Cómo crear un grupo de menú

Un grupo de menú es una colección de elementos de menú que comparten ciertas características. Con un grupo, puedes hacer lo siguiente:

Puedes crear un grupo anidando elementos <item> en un elemento <group> del recurso de menú o especificando un ID de grupo con el método add().

Este es un ejemplo de un recurso de menú que incluye un grupo:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_save"
          android:icon="@drawable/menu_save"
          android:title="@string/menu_save" />
    <!-- menu group -->
    <group android:id="@+id/group_delete">
        <item android:id="@+id/menu_archive"
              android:title="@string/menu_archive" />
        <item android:id="@+id/menu_delete"
              android:title="@string/menu_delete" />
    </group>
</menu>

Los elementos que están en el grupo aparecen en el mismo nivel que el primer elemento: los tres elementos del menú son elementos del mismo nivel. Sin embargo, puedes modificar los rasgos de los dos elementos del grupo haciendo referencia al ID del grupo y usando los métodos anteriores. El sistema nunca separará los elementos agrupados. Por ejemplo, si declaras android:showAsAction="ifRoom" para cada elemento, ambos aparecerán en la barra de acciones o en el menú ampliado de acciones.

Usa elementos de menú que se pueden activar

Figura 5: Un submenú con elementos que se pueden activar.

Un menú puede ser una interfaz útil a los efectos de activar y desactivar opciones, usar una casilla de verificación para opciones independientes o usar botones de selección para grupos de opciones mutuamente excluyentes. En la figura 5, se muestra un submenú con elementos que se pueden activar mediante botones de selección.

Puedes definir el comportamiento de activación para elementos individuales del menú con el atributo android:checkable del elemento <item> o para todo un grupo con el atributo android:checkableBehavior del elemento <group>. Por ejemplo, todos los elementos de este grupo del menú se pueden activar con un botón de selección:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">
        <item android:id="@+id/red"
              android:title="@string/red" />
        <item android:id="@+id/blue"
              android:title="@string/blue" />
    </group>
</menu>

El atributo android:checkableBehavior acepta una de las siguientes opciones:

single
Solo se puede marcar un elemento del grupo, lo que genera botones de selección.
all
Se pueden marcar todos los elementos, lo que genera casillas de verificación.
none
No se puede activar ningún elemento.

Puedes aplicar un estado activado predeterminado a un elemento con el atributo android:checked del elemento <item> y cambiarlo en el código con el método setChecked().

Cuando se selecciona un elemento que se puede activar, el sistema llama al método de devolución de llamada correspondiente del elemento seleccionado, como onOptionsItemSelected(). Aquí es donde configuras el estado de la casilla de verificación, ya que estas y los botones de selección no cambian de estado automáticamente. Puedes consultar el estado actual del elemento (como estaba antes de que el usuario lo seleccionara) con isChecked() y, a continuación, establecer el estado activado con setChecked(). Esto se muestra en el siguiente ejemplo:

Kotlin

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.vibrate, R.id.dont_vibrate -> {
            item.isChecked = !item.isChecked
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

Java

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.vibrate:
        case R.id.dont_vibrate:
            if (item.isChecked()) item.setChecked(false);
            else item.setChecked(true);
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

Si no estableces el estado activado de esta manera, el estado visible de la casilla de verificación o el botón de selección no cambiará cuando el usuario lo seleccione. Si estableces el estado, la actividad preserva el estado activado del elemento de manera que, cuando el usuario abra el menú más tarde, el estado activado que estableciste será visible.

Cómo agregar elementos de menú basados en un intent

A veces, deseas que un elemento de menú inicie una actividad con un Intent, ya sea una actividad en tu app o en otra. Cuando conoces el intent que deseas usar y tienes un elemento de menú específico que inicia el intent, puedes ejecutarlo con startActivity() durante el método de devolución de llamada correspondiente del elemento seleccionado, como la devolución de llamada onOptionsItemSelected().

Sin embargo, si no estás seguro de que el dispositivo del usuario contenga una app que maneje el intent, agregar un elemento de menú que lo invoque puede dar como resultado un elemento de menú que no funcione, ya que el intent puede no resolverse en una actividad. Para solucionar esto, Android te permite agregar dinámicamente elementos al menú cuando encuentra actividades en el dispositivo que controlan el intent.

Para agregar elementos de menú en función de actividades disponibles que aceptan un intent, haz lo siguiente:

  1. Define un intent con la categoría CATEGORY_ALTERNATIVE, CATEGORY_SELECTED_ALTERNATIVE o ambas, además de otros requisitos.
  2. Llama a Menu.addIntentOptions(). Android buscará apps que puedan realizar el intent y las agregará al menú.

Si no hay apps instaladas que satisfagan el intent, no se agregará ningún elemento de menú.

Esto se muestra en el siguiente ejemplo:

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    super.onCreateOptionsMenu(menu)

    // Create an Intent that describes the requirements to fulfill, to be
    // included in the menu. The offering app must include a category value
    // of Intent.CATEGORY_ALTERNATIVE.
    val intent = Intent(null, dataUri).apply {
        addCategory(Intent.CATEGORY_ALTERNATIVE)
    }

    // Search and populate the menu with acceptable offering apps.
    menu.addIntentOptions(
            R.id.intent_group,  // Menu group to which new items are added.
            0,                  // Unique item ID (none).
            0,                  // Order for the items (none).
            this.componentName, // The current activity name.
            null,               // Specific items to place first (none).
            intent,             // Intent created above that describes the requirements.
            0,                  // Additional flags to control items (none).
            null)               // Array of MenuItems that correlate to specific items (none).

    return true
}

Java

@Override
public boolean onCreateOptionsMenu(Menu menu){
    super.onCreateOptionsMenu(menu);

    // Create an Intent that describes the requirements to fulfill, to be
    // included in the menu. The offering app must include a category value
    // of Intent.CATEGORY_ALTERNATIVE.
    Intent intent = new Intent(null, dataUri);
    intent.addCategory(Intent.CATEGORY_ALTERNATIVE);

    // Search and populate the menu with acceptable offering apps.
    menu.addIntentOptions(
         R.id.intent_group,         // Menu group to which new items are added.
         0,                         // Unique item ID (none).
         0,                         // Order for the items (none).
         this.getComponentName(),   // The current activity name.
         null,                      // Specific items to place first (none).
         intent,                    // Intent created above that describes the requirements.
         0,                         // Additional flags to control items (none).
         null);                     // Array of MenuItems that correlate to specific items (none).

    return true;
}

Por cada actividad encontrada que proporciona un filtro de intents que coincida con el intent definido, se agrega un elemento de menú y se usa el valor de android:label del filtro de intents como título del elemento de menú y el ícono de la app como ícono del elemento en cuestión. El método addIntentOptions() muestra la cantidad de elementos de menú agregados.

Cómo permitir que la actividad se agregue a otros menús

Puedes ofrecer los servicios de tu actividad a otras apps para que se pueda incluir tu app en el menú de otras (se revierten los roles descritos anteriormente).

Para que se incluya en los menús de otras apps, define un filtro de intents de la manera habitual, pero incluye los valores CATEGORY_ALTERNATIVE o CATEGORY_SELECTED_ALTERNATIVE, o ambos, para la categoría del filtro de intents. Esto se muestra en el siguiente ejemplo:

<intent-filter label="@string/resize_image">
    ...
    <category android:name="android.intent.category.ALTERNATIVE" />
    <category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
    ...
</intent-filter>

Obtén más información para crear filtros de intents en Intents y filtros de intents.