Inicio Android Menús en Android (II): Menús Contextuales

Menús en Android (II): Menús Contextuales

por sgoliver

En el artículo anterior del curso ya vimos cómo crear menús y submenús básicos para nuestras aplicaciones Android. Sin embargo, existe otro tipo de menús que nos pueden ser muy útiles en determinados contextos: los menús contextuales. Este tipo de menú siempre va asociado a un control concreto de la pantalla y se muestra al realizar una pulsación larga sobre éste. Suele mostrar opciones específicas disponibles únicamente para el elemento pulsado. Por ejemplo, en un control de tipo lista podríamos tener un menú contextual que apareciera al pulsar sobre un elemento concreto de la lista y que permitiera editar su texto o eliminarlo de la colección.

NOTA [Android 3.0 o superior]: a diferencia de los menús de aplicación, para los que ya dijimos que entraron en desuso a partir de la versión 3 de Android en favor de la action bar, los menús contextuales pueden seguir utilizándose sin ningún problema aunque también se recomienda sustituirlos por acciones contextuales en la action bar, pero este tema no lo trataremos en este artículo.

Pues bien, la creación y utilización de este tipo de menús es muy parecida a lo que ya vimos para los menús y submenús básicos, pero presentan algunas particularidades que hacen interesante tratarlos al margen del resto en este nuevo artículo.

Empecemos por un caso sencillo. Vamos a partir de un proyecto nuevo, que ya debe contener por defecto una etiqueta de texto con un Hello World).

Vamos a añadir en primer lugar un menú contextual que aparezca al pulsar sobre la etiqueta de texto. Para ello, lo primero que vamos a hacer es indicar en el método onCreate() de nuestra actividad principal que la etiqueta tendrá asociado un menú contextual. Esto lo conseguimos con una llamada a registerForContextMenu():

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    //Obtenemos las referencias a los controles
    lblMensaje = (TextView)findViewById(R.id.LblMensaje);

    //Asociamos los menús contextuales a los controles
    registerForContextMenu(lblMensaje);
}

A continuación, igual que hacíamos con onCreateOptionsMenu() para los menús básicos, vamos a sobreescribir en nuestra actividad el evento encargado de construir los menús contextuales asociados a los diferentes controles de la aplicación. En este caso el evento se llama onCreateContextMenu(), y a diferencia de onCreateOptionsMenu() éste se llama cada vez que se necesita mostrar un menú contextual, y no una sola vez al inicio de la aplicación. En este evento actuaremos igual que para los ménus básicos, inflando el menú XML que hayamos creado con las distintas opciones, o creando a mano el menú mediante el método add() [para más información leer el artículo anterior]. En nuestro ejemplo hemos definido un menú en XML llamado «menu_ctx_etiqueta.xml«:

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

<item android:id="@+id/CtxLblOpc1"
	android:title="OpcEtiqueta1"></item>
<item android:id="@+id/CtxLblOpc2"
	android:title="OpcEtiqueta2"></item>

</menu>

Por su parte el evento onCreateContextMenu() quedaría de la siguiente forma:

@Override
public void onCreateContextMenu(ContextMenu menu, View v,
    		                    ContextMenuInfo menuInfo)
{
    super.onCreateContextMenu(menu, v, menuInfo);

    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu_ctx_etiqueta, menu);
}

Por último, para implementar las acciones a realizar tras pulsar una opción determinada del menú contextual vamos a implementar el evento onContextItemSelected() de forma análoga a cómo hacíamos con onOptionsItemSelected() para los menús básicos:

@Override
public boolean onContextItemSelected(MenuItem item) {

    switch (item.getItemId()) {
        case R.id.CtxLblOpc1:
            lblMensaje.setText("Etiqueta: Opcion 1 pulsada!");
            return true;
        case R.id.CtxLblOpc2:
            lblMensaje.setText("Etiqueta: Opcion 2 pulsada!");
            return true;
        default:
            return super.onContextItemSelected(item);
    }
}

Con esto, ya tendríamos listo nuestro menú contextual para la etiqueta de texto de la actividad principal, y como veis todo es prácticamente análogo a cómo construimos los menús y submenús básicos en el artículo anterior. En este punto ya podríamos ejecutar el proyecto en el emulador y comprobar su funcionamiento. Para ello, una vez iniciada la aplicación tan sólo tendremos que realizar una pulsación larga sobre la etiqueta de texto. En ese momento debería aparecer el menú contextual, donde podremos seleccionar cualquier de las dos opciones definidas.

Ahora vamos con algunas particularidades. Los menús contextuales se utilizan a menudo con controles de tipo lista, lo que añade algunos detalles que conviene mencionar. Para ello vamos a añadir a nuestro ejemplo una lista con varios datos de muestra y vamos a asociarle un nuevo menú contextual. Modificaremos el layout XML de la ventana principal para añadir el control ListView y modificaremos el método onCreate() para obtener la referencia al control, insertar vaios datos de ejemplo, y asociarle un menú contextual:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    //Obtenemos las referencias a los controles
    lblMensaje = (TextView)findViewById(R.id.LblMensaje);
    lstLista = (ListView)findViewById(R.id.LstLista);

    //Rellenamos la lista con datos de ejemplo
    String[] datos =
        new String[]{"Elem1","Elem2","Elem3","Elem4","Elem5"};

    ArrayAdapter<String> adaptador =
        new ArrayAdapter<String>(this,
            android.R.layout.simple_list_item_1, datos);

    lstLista.setAdapter(adaptador);

    //Asociamos los menús contextuales a los controles
    registerForContextMenu(lblMensaje);
    registerForContextMenu(lstLista);
}

Como en el caso anterior, vamos a definir en XML otro menú para asociarlo a los elementos de la lista, lo llamaremos «menu_ctx_lista«:

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

<item android:id="@+id/CtxLstOpc1"
	android:title="OpcLista1"></item>
<item android:id="@+id/CtxLstOpc2"
	android:title="OpcLista2"></item>

</menu>

Como siguiente paso, y dado que vamos a tener varios menús contextuales en la misma actividad, necesitaremos modificar el evento onCreateContextMenu() para que se construya un menú distinto dependiendo del control asociado. Esto lo haremos obteniendo el ID del control al que se va a asociar el menú contextual, que se recibe en forma de parámetro (View v) en el evento onCreateContextMenu(). Utilizaremos para ello una llamada al método getId() de dicho parámetro:

@Override
public void onCreateContextMenu(ContextMenu menu, View v,
    		                    ContextMenuInfo menuInfo)
{
    super.onCreateContextMenu(menu, v, menuInfo);

    MenuInflater inflater = getMenuInflater();

    if(v.getId() == R.id.LblMensaje)
        inflater.inflate(R.menu.menu_ctx_etiqueta, menu);
    else if(v.getId() == R.id.LstLista)
    {
        AdapterView.AdapterContextMenuInfo info =
            (AdapterView.AdapterContextMenuInfo)menuInfo;

        menu.setHeaderTitle(
            lstLista.getAdapter().getItem(info.position).toString());

        inflater.inflate(R.menu.menu_ctx_lista, menu);
    }
}

Vemos cómo en el caso del menú para el control lista hemos ido además un poco más allá, y hemos personalizado el título del menú contextual [mediante setHeaderTitle()] para que muestre el texto del elemento seleccionado en la lista. Para hacer esto nos hace falta saber la posición en la lista del elemento seleccionado, algo que podemos conseguir haciendo uso del último parámetro recibido en el evento onCreateContextMenu(), llamado menuInfo. Este parámetro contiene información adicional del control que se ha pulsado para mostrar el menú contextual, y en el caso particular del control ListView contiene la posición del elemento concreto de la lista que se ha pulsado. Para obtenerlo, convertimos el parámetro menuInfo a un objeto de tipo AdapterContextMenuInfo y accedemos a su atributo position tal como vemos en el código anterior.

La respuesta a este nuevo menú se realizará desde el mismo evento que el anterior, todo dentro de onContextItemSelected(). Por tanto, incluyendo las opciones del nuevo menú contextual para la lista el código nos quedaría de la siguiente forma:

@Override
public boolean onContextItemSelected(MenuItem item) {

    AdapterContextMenuInfo info =
        (AdapterContextMenuInfo) item.getMenuInfo();

    switch (item.getItemId()) {
        case R.id.CtxLblOpc1:
            lblMensaje.setText("Etiqueta: Opcion 1 pulsada!");
            return true;
        case R.id.CtxLblOpc2:
            lblMensaje.setText("Etiqueta: Opcion 2 pulsada!");
            return true;
        case R.id.CtxLstOpc1:
            lblMensaje.setText("Lista[" + info.position + "]: Opcion 1 pulsada!");
            return true;
        case R.id.CtxLstOpc2:
            lblMensaje.setText("Lista[" + info.position + "]: Opcion 2 pulsada!");
            return true;
        default:
            return super.onContextItemSelected(item);
    }
}

Como vemos, aquí también utilizamos la información del objeto AdapterContextMenuInfo para saber qué elemento de la lista se ha pulsado, con la única diferencia de que en esta ocasión lo obtenemos mediante una llamada al método getMenuInfo() de la opción de menú (MenuItem) recibida como parámetro.

Si volvemos a ejecutar el proyecto en este punto podremos comprobar el aspecto de nuestro menú contextual al pulsar cualquier elemento de la lista:

menu-contextual

En Android 4 sería muy similar:

android-context-menu

A modo de resumen, en este artículo hemos visto cómo crear menús contextuales asociados a determinados elementos y controles de nuestra interfaz de la aplicación. Hemos visto cómo crear menús básicos y algunas particularidades que existen a la hora de asociar menús contextuales a elementos de un control de tipo lista. Para no alargar este artículo dedicaremos un tercero a comentar algunas opciones menos frecuentes, pero igualmente útiles, de los menús en Android.

Puedes consultar y/o descargar el código completo de los ejemplos desarrollados en este artículo accediendo a la pagina del curso en GitHub.

Curso de Programación Android en PDF

Este curso también está disponible en PDF. Descubre cómo conseguirlo…

¿Te ha sido de utilidad el Curso de Programación Android? ¿Quieres colaborar de forma económica con el proyecto? Puedes contribuir con cualquier cantidad, unos céntimos, unos euros, cualquier aportación será bienvenida. Además, si tu aportación es superior a una pequeña cantidad simbólica recibirás como agradecimiento un documento con la última versión del curso disponible en formato PDF. Sea como sea, muchas gracias por colaborar!

Más información:

También te puede interesar

19 comentarios

Desarrollo en Android | sgoliver.net blog 30/03/2011 - 16:12

[…] Menús en Android (II): Menús Contextuales [Nuevo!] […]

Responder
Txusms 06/06/2011 - 18:47

Hola @sgoliver,

Estoy siguiendo el curso en PDF y estoy llegando donde nunca abría imaginado. Pero…, como no siempre hay dudas.

Tengo un botón que me abre el Barcode Scanner, este me devuelve el código leído, y dependiendo de si ese producto lo tengo guardado o no, quiero mostrar un menú distinto.

No se si tengo que utilizar un menú contextual o uno de opciones. Tampoco se como llamarlo para que lo muestre.

¿Me puedes orientar?

Gracias.

Responder
Fabian Garcia 15/07/2011 - 23:39

Excelentes artículos!!!

Me los leo en el orden que aparece en el listado de artículos y aquí terminan con la promesa de una tercera parte del tema «Menus en Android» que por supuesto, esperare con ansia.

Mucho éxito y gracias!!

Responder
sgoliver 16/07/2011 - 16:46

Es cierto Fabian, tenía previsto un artículo más sobre menús, pero se colaron por delante otros temas a petición popular. De cualquier forma no lo olvido, espero poder publicarlo pronto. Gracias por seguir mis artículos, y espero que sigas disfrutando del curso. Saludos.

Responder
carlos 21/07/2011 - 0:17

la verdad los felicito por el blog..impresionante mu ha ayudado en cantidad para mi proyecto final. gracias!!

Responder
waldo 31/01/2012 - 23:40

Buenas tardes.
Tengo un problema que no puedo resolver con los menus.
cuando corro mi aplicacion no logro visualizar el menu no me manda ningun tipo de error lo he intentado de las dos formas, por xml y por codigo y ninguna forma logro que me aparesca el menu, mi version de android es en el emulador es 4.0.3.
no se cual es el motivo espero y puedan ayudar saludos.

Responder
Mario 04/02/2012 - 21:36

Waldo, intenta cambiar la versión de Android a 2.1, 2.2.o 2.3 y nos dices si se soluciona tu problema

Responder
Felipe 30/04/2012 - 16:34

notable…. de verdad que muchas gracias, me ha ayudado montones este curso.

Responder
kenneth 16/05/2012 - 14:24

excelente tutorial, pero tengo una duda

¿como puedo hacer para que el menu al pulsar la lista salga al pulsar el elemento una vez y no tener que dejar pulsado el elemento unos segundos?

gracias

Responder
Aner 26/05/2012 - 18:58

Visto este buen tutorial, he decidido implementar a mi textview el menu de contexto, pero parece ser que crea conclicto con onTouchListener… Hay alguna solucion?

Muchisimas gracias por el tutorial!!!!!

Responder
Emilio 24/06/2012 - 10:03

Gran Blog, Excelente trabajo. Estoy realizando una aplicacion simple de anotacion para un juego de cartas, tengo dos botones, cuando pulsas en uno de ellos, se ejecuta una funcion que realiza una anotacion de un punto en un text view que hay al lado. Hasta aqui bien, el problema es que en este juego se pueden anotar mas valores: 3, 6, 9, 12, … y para ello implemento un menu contextual en los botones. el menu es el mismo para los dos, pero no logro saber en la funcion onContextItemSelected cual es el boton que ha pulsado el usuario, para realizar la anotacion al equipo1 o al equipo 2. ¿¿Alguien sabe como puedo recuperar este parametro??

Gracias

Responder
Juan 20/08/2012 - 12:55

pero como hacemos el menu para que aparezca en la v4?

Responder
Miguel 22/11/2012 - 0:34

Hola yo estoy siguiendo los tutoriales en la versión 4.1 de android y la verdad ya verifiqué todo el código y no funciona como los ejemplos mostrados en el Blog, solo aparece la lista, pero al presionar e cada item no sale ningún mensaje y no despliega ningún menú :(
alguien puede ayudarme o comentar si esproblema de la versión

gracias

Responder
Diego 18/09/2013 - 1:56

Hola, estoy tratando de hacer un menu en mi proyecto, pero resulta que por cuestiones de desarrollo estoy trabajando con extends View, y no puedo realizar el menu, sabes de pronto como hacerlo?
Gracias

Responder
Nelson Carta 31/12/2013 - 1:39

Hombre: muchas gracias por tutorial, está excelente. Me resultó algo difícil comprender el INFLATER, Vendría bien una traducción más precisa, eso de «INFLAR» un menú la verdad se presta a confusión. Según lo que investigue: inflater es: «convertir una archivo .xml en un objeto java» ó también: «Crea una instancia de un archivo XML de diseño en sus correspondientes objetos View». Así la cosa está bastante clara.

Responder
Martin Urias 03/06/2014 - 20:52

Me gustaria saber como hacerlo en un layout diferente al activity_main, o que cada layout tenga su propio menu contextual.
Saludos.

Responder
Curso Programación Android por Salvador Gómez – Indice de Contenidos | Miguel Moyetones 17/06/2015 - 21:24

[…] Menús en Android (II): Menús Contextuales [v3] […]

Responder
Jesús Frías 08/03/2017 - 3:49

No logro hacer aparecer el menú en Android, cuando pulso en un elemento de la lista no pasa nada. ¿Alguien sabe como hacerlo en Android 4+?

Responder
Daniel 31/12/2017 - 20:54

El menu contextual se puede royar en 90º … alguien sabe ?

Responder

Responder a Nelson Carta

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información. Aceptar Más Información

Política de Privacidad y Cookies