Agregar menús

Prueba el estilo de Compose
Jetpack Compose es el kit de herramientas de IU recomendado para Android. Aprende a 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 del usuario conocida y coherente, usa las APIs de Menu para presentar acciones del usuario y otras opciones en tus actividades.

Una imagen que muestra un ejemplo de menú ampliado
Figura 1: Menú que se activa cuando se presiona un ícono y 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 colocas las acciones que tienen un impacto global en la app, como "Buscar", "Redactar correo electrónico" y "Configuración".

Consulta la sección Crea 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.

El modo de acción contextual muestra los elementos de acción que afectan el contenido seleccionado en una barra en la parte superior de la pantalla y 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án anclados a la vista que invoca el menú. Es útil para proporcionar una ampliación de acciones relacionadas con contenido específico o para proporcionar opciones para la 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ú, Android proporciona un formato XML estándar para definir los elementos del menú. En lugar de compilar un menú en el código de la actividad, define un menú y todos sus elementos en un recurso de menú XML. Luego, puedes aumentar el recurso de menú (cargarlo como un objeto Menu) en tu actividad o fragmento.

Usar un recurso de menú es una práctica recomendada por las siguientes razones:

  • Es más fácil visualizar la estructura del menú en XML.
  • Separa el contenido del menú del código de comportamiento de tu 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/ de tu proyecto y compílalo 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ú. que 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 activo y la visibilidad. Para obtener más información, consulta la sección Cómo crear un grupo del 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 un ID de recurso que es único para el 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 ícono del elemento.
android:title
Es la referencia a una cadena que se usa como título del elemento.
android:showAsAction
Es la especificación de cuándo y cómo se muestra este elemento 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 compatibles, consulta la documentación sobre el recurso de menú.

Puedes agregar un submenú a un elemento de cualquier menú si agregas un elemento <menu> como elemento secundario de un <item>. Los submenús son útiles cuando tu app tiene muchas funciones que se pueden organizar en temas, como los elementos de la barra de menú de una app para PC, como Archivo, Editar y Ver. 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

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

Imagen que muestra la barra de la app de Hojas de cálculo de Google
Figura 2: La app de Hojas de cálculo de Google que muestra varios botones, incluido el botón de menú ampliado de acciones.

Puedes declarar elementos para el menú de opciones desde las subclases Activity o Fragment. Si tanto la actividad como los fragmentos declaran elementos para el menú de opciones, los elementos se combinan en la IU. Los elementos de la actividad aparecen primero y, luego, 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 de 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 recuperarlos 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 tu actividad. Este método pasa el MenuItem seleccionado. Puedes identificar el elemento llamando 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 número entero dado 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 el valor falso.

Si la actividad incluye fragmentos, el sistema llama primero a onOptionsItemSelected() para la actividad y, luego, para cada fragmento en el orden en que se agregan, hasta que uno muestre true o se llame a 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ú propagas y no vuelve a llamar a onCreateOptionsMenu(), 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 quieres modificar el menú de opciones en función de eventos que ocurran durante el ciclo de vida de la actividad, puedes hacerlo en el método onPrepareOptionsMenu(). Este método te pasa el objeto Menu como se encuentra actualmente para que puedas modificarlo, por ejemplo, agregando, quitando o inhabilitando elementos. Los fragmentos también proporcionan una devolución de llamada onPrepareOptionsMenu().

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

Crea un menú contextual

Imagen que muestra un menú contextual flotante
Figura 3: Un menú contextual flotante

Un menú contextual ofrece acciones que afectan un elemento o marco contextual específico en la IU. Puedes proporcionar un menú contextual para cualquier vista, pero se usan con mayor frecuencia para elementos en una RecylerView o en otras colecciones de vistas en las que el usuario puede realizar acciones directas 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 diálogo, cuando el usuario mantiene presionada una vista que declara compatibilidad con 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, o 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.

Cómo crear un menú contextual flotante

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

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

    Si tu actividad usa un RecyclerView y quieres que cada elemento proporcione el mismo menú contextual, registra todos los elementos para un menú contextual pasando 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 al método onCreateContextMenu(). Aquí es donde defines los elementos de menú, por lo general a través del aumento de 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 el View que selecciona el usuario 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 ampliar.

  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 correspondiente.

    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 puedes asignar a cada elemento de menú en XML con el atributo android:id, como se muestra en Define 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, recibe la devolución de llamada primero. Cuando se llama a la superclase cuando no está controlada, el sistema pasa el evento al método de devolución de llamada correspondiente en cada fragmento, uno a la vez, en el orden en que se agregó cada fragmento, hasta que se muestre true o false. Las implementaciones predeterminadas para Activity y android.app.Fragment muestran false, por lo que siempre debes llamar a la superclase cuando no se controle.

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 selecciona un elemento para habilitar este modo, aparece una barra de acciones contextuales en la parte superior de la pantalla que presenta las acciones que el usuario puede realizar en los elementos seleccionados. Mientras este modo está habilitado, el usuario puede seleccionar varios elementos (si tu app lo admite) y puede anular la selección de elementos y seguir navegando dentro de la actividad. El modo de acción está inhabilitado 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 el caso de las vistas que proporcionan acciones contextuales, por lo general, se invoca el modo de acción contextual cuando se produce uno de estos dos eventos o ambos:

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

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

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

Las siguientes secciones describen la configuración necesaria para cada escenario.

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 los 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 para el 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 con el 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 es útil para indicar cuántos elementos se seleccionaron.

    En el ejemplo anterior, se configura la variable actionMode en null cuando se destruye el modo de acción. En el siguiente paso, consulta cómo se inicializa y cómo puede resultar útil guardar la variable de miembro en tu actividad o fragmento.

  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, puedes realizar cambios en la barra de acciones contextuales en respuesta a otros eventos. En el ejemplo anterior, se usa ActionMode para garantizar que la instancia ActionMode no se vuelva a crear si ya está activa. Para ello, se verifica si el miembro es nulo antes de iniciar el modo de acción.

Crea un menú emergente

Imagen que muestra un menú emergente en la app de Gmail anclado al botón ampliado en la esquina superior derecha.
Figura 4: Un menú emergente en la app de Gmail anclado al botón ampliado en la esquina superior derecha

Un PopupMenu es un menú modal anclado a una View. Aparece debajo de la vista ancla si hay espacio o, de lo contrario, por encima de ella. 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 como Add que produce un menú emergente con diferentes opciones de Add
  • 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 la Context de la app actual y la View a la que está anclado 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í te mostramos 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 presiona 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 seleccione un elemento de menú, implementa la interfaz PopupMenu.OnMenuItemClickListener y regístrala con tu PopupMenu llamando a setOnMenuItemclickListener(). Cuando el usuario selecciona un elemento, el sistema llama a la devolución de llamada onMenuItemClick() en tu 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;
    }
}

Crea un grupo de menús

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> dentro de un elemento <group> en el 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 separa 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.

Cómo usar elementos de menú que se pueden activar

Figura 5: Submenú con elementos que se pueden activar.

Un menú puede ser una interfaz útil para activar y desactivar opciones, usar una casilla de verificación para opciones independientes o botones de selección para grupos de opciones mutuamente excluyentes. En la Figura 5, se muestra un submenú con elementos que se pueden marcar con 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 en el 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 hace que se muestren 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í se configura el estado de la casilla de verificación, ya que las casillas de verificación y los botones de selección no cambian su estado automáticamente. Puedes consultar el estado actual del elemento, como estaba antes de que el usuario lo seleccionara, con isChecked() y, luego, 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 configuras el estado activado de esta manera, el estado visible de la casilla de verificación o del botón de selección no cambiará cuando el usuario lo seleccione. Cuando estableces el estado, la actividad conserva el estado activado del elemento para que, cuando el usuario abra el menú más tarde, el estado activado que estableciste sea visible.

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

Es posible que quieras que un elemento de menú inicie una actividad con un Intent, ya sea una actividad en tu app o en otra. Si conoces el intent que quieres usar y tienes un elemento de menú específico que lo inicia, 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 controle 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 podría no resolverse en una actividad. Para solucionar este problema, Android te permite agregar dinámicamente elementos de menú al menú cuando encuentra actividades en el dispositivo que controlan tu intent.

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

  1. Define un intent con la categoría CATEGORY_ALTERNATIVE o CATEGORY_SELECTED_ALTERNATIVE, o ambas opciones, además de otros requisitos.
  2. Llama a Menu.addIntentOptions(). Android busca apps que puedan realizar el intent y las agrega 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 en el android:label del filtro de intents como título del elemento de menú y el ícono de la app como ícono del elemento de menú. El método addIntentOptions() muestra la cantidad de elementos de menú agregados.

Permite que la actividad se agregue a otros menús

Puedes ofrecer los servicios de tu actividad a otras apps para que esta se pueda incluir en el menú de otras personas, lo que revierte los roles descritos anteriormente.

Para que se incluya en otros menús de apps, define un filtro de intents como de costumbre, 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 escribir filtros de intents en Intents y filtros de intents.