Menús

De MediaWiki
Ir a la navegación Ir a la búsqueda

Introducción

  • Nesta unidade imos ver como xestionar menús, submenús e menú contextuais.
  • A seguinte imaxe amosa os menús na Action Bar da aplicación

Actionbar.png

  • 1: Icona da App e nome
  • 2: Dúas iconas de menús da aplicación
  • 3: Menú OverFlow que equivale ao botón Menú da Botonera.
  • Os menús poden poñerse na Action Bar dende a versión 3.0 de Android.


  • Esta barra pasa a chamarse AppBar a partires da versión Android 5 (API 21).


  • Para versións anteriores á 3.0 os menús víanse como na parte inferior da seguinte imaxe:

Options menu.png


  • A seguinte imaxe amosa 3 botóns de menú na Barra de Acción e o menú Overflow

Actionbar-item-withtext.png


  • Nesta imaxe vese como un dos menús da action bar ten submenús:

Actionbar-shareaction2x.png



  • Finalmente as seguintes imaxes amosan Menús Contextuais
    • Flotantes (esquerda)
    • ou na barra de accións (dereita)

Menu-context.png


Menús e submenús básicos

  • Imos ver como personalizar a ActionBar (chámase ToolBar e forma parte da AppBar, a partires da versión API 21) e que aparezan opcións de menú:
PDM Biblioteca compat 1.jpg
Imaxe obtida desta web



  • Nota:
  • Indicar que podemos consultar o tamaño recomendado das iconas que van na AppBar neste enlace.
  • Podemos obter iconas no sitio web: http://www.iconarchive.com/ (intentar utilizar os que teñan licenza free).


  • Imos realizar unha aplicación con 3 opcións de menú (un deles con submenús e outro cunha icona na Barra de Acción).
  • Se queremos que a ActionBar (ToolBar dentro da AppBar a partires da versión API 21):
  • Teña o mesmo aspecto en todas as versións de Android.
  • Posibilidade de facer uso da interface de usuario Material Design (introducido a partires da API 21).
Teremos que facer uso das bibliotecas de compatibilidade e facer que a nosa activity derive de AppCompactActivity.
Ao facelo teremos que cambiar o deseño por un de tipo AppCompact.
Podedes consultar como facelo neste enlace: http://wiki.cifprodolfoucha.es/index.php?title=PDM_UD1_Bibliotecas_de_compatibilidade



Empregando AppCompactActivity

  • Se estades a desenvolver un proxecto e as vosos activities derivan de dita clase para ter compatibilidade con versións de Android anteriores, podemos facer que a AppBar apareza de dúas formas:
  • Empregando un theme (estilo) que incorpore a ActionBar.
  • Empregando un theme que non incorpore' o ActionBar e engadindo ao Layout da Activity o View que vai representar a ActionBar.
  • A opción recomendada é a segunda, xa que temos un control completo sobre o aspecto e posición da ActionBar (ToolBar).




O código que hai que engadir na activity no método 'onCreate' é:
1         Toolbar myToolbar = findViewById(R.id.toolbar_UD04_01_Menus);
2         setSupportActionBar(myToolbar);
Nota: Indicar que myToolbar representa a ToolBar e podemos aplicarlle diferentes métodos coma hide() para ocultala.



  • A nivel do asistente de Android Studio podemos crear unha AppBar (que inclúe ToolBar) con efectos coma facerse invisible automaticamente cando hai un scroll, poñer imaxes de fondo,...o único que tedes que facer é arrastrar o compoñentes AppBarLayout en vez do ToolBar de antes.




Recursos Implicados

  • Os menús defínense nun recurso xml en res/menu/nome_ficheiro.xml


  • Dito recurso terá coma elementos:
    • <menu>: elemento raíz. Contén <item> e <group>
    • <item>: representa un elemento de menú.
      • Tería que ter un elemento <menu> dentro de <item> para crear un submenú.


  • Arrastrade dous 'menuitem' e cambiade as súas propiedades:
  • id: mniPrimeiro
  • Texto: Primeiro
  • id:mniSegundo
  • Texto: Segundo


IMPORTANTE: Se estades a empregar unha AppCompactActivity asegurádevos de que estea definido o espazo de nomes app na etiqueta 'menu' no arquivo xml, da forma: xmlns:app="http://schemas.android.com/apk/res-auto"

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <menu xmlns:app="http://schemas.android.com/apk/res-auto"
 3     xmlns:android="http://schemas.android.com/apk/res/android">
 4 
 5     <item
 6         android:id="@+id/mniPrimeiro"
 7         android:title="Primeiro"
 8         />
 9     <item
10         android:id="@+id/mniSegundo"
11         android:title="Segundo"></item>
12 </menu>


  • Agora comentaremos algúns dos atributos que podemos cambiar.
Lembrar que o podemos facer graficamente ou directamente no editor na vista XML.
  • Atributo android:icon: Icona asociada a esta opción de menú. Lembrade que xa vimos anteriormente como facer uso do Image Asset Store. Agora deberemos escoller a categoría 'Action bar and Tab Icons'.
  • Atributo android:showAsAction (se a activity deriva da clase Activity):
Atributo app:showAsAction (se a activity deriva da clase AppCompactActivity)
IMPORTANTE: Se temos importada a librería de compatibilidade AppCompactActivity no build.gradle nos vai a obrigar a empregar esta opción (app:) e polo tanto teremos que facer que a activity derive de AppCompactActivity.
PDM menu 11.jpg
  • Pode ter os seguintes valores:
    • never: nunca amosa o item de menú na barra de acción.
    • ifRoom: se hai espazo na barra de acción o amosa.
    • always: amosa sempre na barra de acción.
    • withText: se temos unha icona, por defecto non amosa o texto. Se queremos que amose os dúos poñeremos este valor.
    • collapseActionView: cando a acción dun elemento de menú (declarada coma android:actionLayout ou android:actionViewClass) é plegable. Dispoñible apartires da versión API 14. Exemplo de uso neste enlace.


  • Atributo android:orderInCategory="Nº Enteiro":
Despois de premer no deseñador de Android Studio na opción 'View all attributes':
PDM menu 12.jpg
Se hai varios ítems indica cal aparecerá primeiro, segundo, etc. Se todos teñen o mesmo valor ou non se pon valor ningún, entón aparecen na orde na que son creados, de esquerda a dereita e de arriba-abaixo.


  • Os elementos de menú que aparecen na barra, xa non aparecen no menú o premer o botón Menú ou "OverFlow", aínda que estean nun group, como se pode apreciar nas imaxes de abaixo.
  • Os valores pódense combinar có caracter ‘|’.


  • O atributo android:onClick funciona igual que nas vistas do recurso xml do Layout.



  • EXEMPLO DE MENÚ NA BARRA DE ACCIÓN CON SUBMENUS
  • A seguinte imaxe, obtense co seguinte recurso xml.

Android 2014 U5 01 Menus 09.jpg


Lembra que xa vimos como engadir novos recursos gráficos cando vimos o ImageView.


 1 <?xml version="1.0" encoding="utf-8"?>
 2 <menu xmlns:app="http://schemas.android.com/apk/res-auto"  xmlns:android="http://schemas.android.com/apk/res/android">
 3 
 4     <item
 5         android:id="@+id/itemAbrir"
 6         android:icon="@drawable/open32"
 7         android:showAsAction="ifRoom"
 8         android:title="Abrir"
 9         android:titleCondensed="Abrir">
10         <menu>
11             <item
12                 android:id="@+id/itemDoc"
13                 android:title="Documento"
14                 android:titleCondensed="Doc."/>
15             <item
16                 android:id="@+id/itemIma"
17                 android:title="Imaxes"
18                 android:titleCondensed="Imax."/>
19             <item
20                 android:id="@+id/itemAudio"
21                 android:title="Audio"
22                 android:titleCondensed="Audio"/>
23         </menu>
24     </item>
25     <item
26         android:id="@+id/itemNovo"
27         android:icon="@drawable/close32"
28         android:showAsAction="ifRoom"
29         android:title="Novo documento"
30         android:titleCondensed="N.Doc.">
31     </item>
32     <item
33         android:id="@+id/itemSair"
34         android:icon="@drawable/exit32"
35         android:showAsAction="ifRoom"
36         android:title="Saír"
37         android:titleCondensed="Saír">
38     </item>
39 
40 </menu>
  • Liñas 6,27,34: Indican o recurso drawable que deben amosar. Estas imaxes deben estar na carpeta /res/drawableXXXXX correspondentes.
  • Liñas 7,28,35: Indican que se hai espazo na barra de acción que amosen eses ítems que teñen ese atributo.
  • Liñas 9,30,37: O atributo android:titleCondensed usarase cando o valor de android:title sexa demasiado longo.
  • Liñas 10-23: Para crear submenús dentro dun menú, volvemos a crear a entrada <menu> dentro de <item>


Agrupamentos

  • Outro elemento que pode ir dentro do elemento <menu>:
    • <group>: un grupo é un conxunto de elementos que teñen certas características.
      • Amosar ou ocultar todos os elementos: setGroupVisible()
      • Habilitar ou deshabilitar todos os elementos: setGroupEnabled()
      • Facer que todos os ítems do group poidan ser presentados en forma de checkbox: setGroupCheckable()
        • Podemos facer que un elemento sexa chequeable usando o atributo android:checkable no elemento <item> ou o
        • group enteiro con 'android:checkableBehavior no elemento <group>.
        • O atributo android:checkableBehavior pode ter as seguintes opcións:
          • single: só un elemento do grupo pode ser checkeado (radiobuttons).
          • all: todos os elementos poden ser checkeados (checkboxs).
          • none: ningún elemento é seleccionable.
        • Se non poñemos nada, os elementos do <group> aparecen como os demais.


  • A seguinte imaxe, ten asociado o seguinte XML.
  • Observar que na barra de acción non collen todos os menús.
  • Observar que hai dous menús (Modo Lectura e Modo Gravación) que poden ser marcados os dous.


 1 <?xml version="1.0" encoding="utf-8"?>
 2 <menu xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android">
 3 
 4     <item
 5         android:id="@+id/itemAbrir"
 6         android:icon="@drawable/open32"
 7         android:showAsAction="always"
 8         android:title="Abrir"
 9         android:titleCondensed="Abrir">
10         <menu>
11             <item
12                 android:id="@+id/itemDoc"
13                 android:title="Documento"
14                 android:titleCondensed="Doc."/>
15             <item
16                 android:id="@+id/itemIma"
17                 android:title="Imaxes"
18                 android:titleCondensed="Imax."/>
19             <item
20                 android:id="@+id/itemAudio"
21                 android:title="Audio"
22                 android:titleCondensed="Audio"/>
23         </menu>
24     </item>
25     <item
26         android:id="@+id/itemNovo"
27         android:icon="@drawable/close32"
28         android:showAsAction="ifRoom"
29         android:title="Novo documento"
30         android:titleCondensed="N.Doc.">
31     </item>
32     <item
33         android:id="@+id/itemSair"
34         android:icon="@drawable/exit32"
35         android:showAsAction="ifRoom"
36         android:title="Saír"
37         android:titleCondensed="Saír">
38     </item>
39 
40     <group
41         android:id="@+id/mgrpModos"
42         android:checkableBehavior="all" >
43         <item
44             android:id="@+id/ModoLect"
45             android:showAsAction="ifRoom"
46             android:title="Modo Lectura"
47             android:titleCondensed="M.Lect.">
48         </item>
49         <item
50             android:id="@+id/ModoRecord"
51             android:showAsAction="ifRoom"
52             android:title="Modo Grabación"
53             android:titleCondensed="M.Grab">
54         </item>
55     </group>
56 
57 </menu>
  • Liñas 35,45,51: Observar como estes ítems non se amosan na barra de acción porque non teñen espazo.
  • Liñas 40-55: Observar como hai un agrupamento de ítems e na liña 42 indícase que todos eles son "chequeables".

Lanzar e procesar o menú

  • Para lanzar o menú debemos cambiar o menú que ten asinada unha determinada Activity e para iso temos que sobrescribir o método onCreateOptionsMenu().
  • O que facemos en "inflar" o xml asociado ao menú (Liña 4) do mesmo xeito que se fai cando se
1     @Override
2     public boolean onCreateOptionsMenu(Menu menu) {
3         // Inflate the menu; this adds items to the action bar if it is present.
4         getMenuInflater().inflate(R.menu.menu_ud04_01_menus, menu);
5         return true;
6     }


  • Cando se preme un ítem dun menú lánzase o evento onOptionsItemSelected e para procesar ese ítem sobrescribir o método onOptionsItemSelected(MenuItem item).
 1 @Override
 2 public boolean onOptionsItemSelected(MenuItem item) {
 3     // Handle action bar item clicks here. The action bar will
 4     // automatically handle clicks on the Home/Up button, so long
 5     // as you specify a parent activity in AndroidManifest.xml.
 6  
 7     int id = item.getItemId();
 8     if (id == R.id.itemAbrir) {
 9 	      return true;
10     }
11     return super.onOptionsItemSelected(item);
12 }
  • Este método devolve un boolean:
    • true: se procesamos un elemento do menú (return true).
    • false: se queremos que o evento siga 'propagándose' polo resto da xerarquía de views do Activity.



  • Se temos os elementos de menú como de tipo 'seleccionable' dentro dun grupo, debemos ser nos os que os marquemos chamando ao método setChecked(boolean valor) e para saber se está chequeado o método getChecked().
 1 @Override
 2 public boolean onOptionsItemSelected(MenuItem item) {
 3  
 4     int id = item.getItemId();
 5     if (id == R.id.mniConCheck) {
 6         if (item.isChecked())     // Está activado antes de premelo, entón o desactivamos
 7               item.setChecked(false);
 8         else
 9               item.setChecked(true);
10               
11 	      
12         return true;
13     }
14     return super.onOptionsItemSelected(item);
15 }

Caso práctico

Se non o temos creado antes, crearemos un novo paquete de nome: Menus como un subpaquete do teu paquete principal.



  • Dentro do paquete Menus crear unha nova 'Empty Activity' de nome: UD04_01_Menus de tipo Launcher e sen compatibilidade.
Modifica o arquivo AndroidManifiest.xml e engade unha label á activity como xa vimos na creación do proxecto base.



Nota: Nas imaxes aparece como label da activity: 'U5_01_XXXX'. Non fagades caso e a vos debería saír: UD06_01_Menus.



As imaxes dos menús

  • Neste caso colocouse en cada recurso res/drawable a imaxe da cara:

PDM menu 15.jpg


Recursos XML

  • O xml do Layout: activity_ud04_01__menus

(Nota: Neste exemplo estamos a empregar un theme que xa amosa a ToolBar. No voso caso pode aparecer ademais o View ToolBar)

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:app="http://schemas.android.com/apk/res-auto"
 4     xmlns:tools="http://schemas.android.com/tools"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent"
 7     tools:context=".Menus.UD04_01_Menus">
 8 
 9     <TextView
10         android:id="@+id/tvTexto_UD04_01_Menus"
11         android:layout_width="wrap_content"
12         android:layout_height="wrap_content"
13         android:layout_marginBottom="8dp"
14         android:layout_marginEnd="8dp"
15         android:layout_marginStart="8dp"
16         android:layout_marginTop="8dp"
17         android:text="TextView"
18         android:textSize="24sp"
19         app:layout_constraintBottom_toBottomOf="parent"
20         app:layout_constraintEnd_toEndOf="parent"
21         app:layout_constraintStart_toStartOf="parent"
22         app:layout_constraintTop_toTopOf="parent" />
23 </android.support.constraint.ConstraintLayout>


  • Creamos un XML có texto das opcións de menú en /res/values/ de nome strings_mnu_ud04_01_menus:
1 <?xml version="1.0" encoding="utf-8"?>
2 <resources>
3     <string name="str_mniItem1_UD04_01_Menus">Opción 1</string>
4     <string name="str_mniItem2_UD04_01_Menus">Opción 2</string>
5     <string name="str_mnuItem3_UD04_01_Menus">Opción 3- Submenús</string>
6     <string name="str_mniItem3_1_UD04_01_Menus">Opción 3- Submenú 1 - Calculadora</string>
7     <string name="str_mniItem3_2_UD04_01_Menus">Opción 3- Submenú 2 - Saír</string>
8 
9 </resources>


  • O xml do 'menú' (modificamos o recurso XML creado por defecto en /res/menu/...): mnu_ud04_01_menus.xml
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <menu xmlns:app="http://schemas.android.com/apk/res-auto"
 3     xmlns:android="http://schemas.android.com/apk/res/android">
 4 
 5     <item
 6         android:id="@+id/mniItem1_04_01_Menus"
 7         android:icon="@drawable/ic_action_emo_basic"
 8         android:orderInCategory="100"
 9         app:showAsAction="always"
10         android:title="@string/str_mniItem1_UD04_01_Menus"/>
11     <item
12         android:id="@+id/mniItem2_04_01_Menus"
13         android:orderInCategory="100"
14         app:showAsAction="never"
15         android:title="@string/str_mniItem2_UD04_01_Menus"/>
16     <item
17         android:id="@+id/mnuItem_3_04_01_Menus"
18         android:orderInCategory="100"
19         app:showAsAction="never"
20         android:title="@string/str_mnuItem3_UD04_01_Menus">
21         <menu>
22             <item
23                 android:id="@+id/mniItem3_1_04_01_Menus"
24                 android:title="@string/str_mniItem3_1_UD04_01_Menus"/>
25             <item
26                 android:id="@+id/mniItem3_2_04_01_Menus"
27                 android:title="@string/str_mniItem3_2_UD04_01_Menus"/>
28         </menu>
29     </item>
30 </menu>
  • Liñas 8,13,18: Observar como todos os ítems teñen o mesmo valor para a ser ordenados.
    • Que o participante no curso probe a cambiar o terceiro ítem a un valor de 99.
  • Liñas 9,14,19: Observar como o primeiro ítem indica always e os demais never á hora de amosar o menú na barra de acción.

O código da Activity

 1 package es.cursoandroid.cifprodolfoucha.aprendiendo.Menus;
 2 
 3 import android.content.Intent;
 4 import android.os.Bundle;
 5 import android.support.v7.app.AppCompatActivity;
 6 import android.view.Menu;
 7 import android.view.MenuItem;
 8 import android.widget.TextView;
 9 import android.widget.Toast;
10 
11 import es.cursoandroid.cifprodolfoucha.aprendiendo.R;
12 
13 public class UD04_01_Menus extends AppCompatActivity {
14 
15     @Override
16     protected void onCreate(Bundle savedInstanceState) {
17         super.onCreate(savedInstanceState);
18         setContentView(R.layout.activity_ud04_01__menus);
19     }
20 
21 
22     @Override
23     public boolean onCreateOptionsMenu(Menu menu) {
24         // Inflate the menu; this adds items to the action bar if it is present.
25         getMenuInflater().inflate(R.menu.mnu_ud04_01_menus, menu);
26         return true;
27     }
28 
29 
30     @Override
31     public boolean onOptionsItemSelected(MenuItem item) {
32         // Handle action bar item clicks here. The action bar will
33         // automatically handle clicks on the Home/Up button, so long
34         // as you specify a parent activity in AndroidManifest.xml.
35 
36         TextView tv = (TextView) findViewById(R.id.tvTexto_UD04_01_Menus);
37         Toast.makeText(getApplicationContext(), "Pulsado elemento: " + item.getTitle().toString(), Toast.LENGTH_SHORT).show();
38 
39         switch (item.getItemId()) {
40             case R.id.mniItem1_04_01_Menus:
41                 tv.setText("Quedarei con esta cara de sorriso cando remate esta tarefa");
42                 return true;
43 
44             case R.id.mniItem2_04_01_Menus:
45                 tv.setText("A opción 2 non ten nada asignado");
46                 return true;
47 
48             case R.id.mniItem3_1_04_01_Menus:
49                 Intent intent = new Intent();
50                 intent.setClassName("com.android.calculator2", "com.android.calculator2.Calculator");
51                 startActivity(intent);
52                 return true;
53 
54             case R.id.mniItem3_2_04_01_Menus:
55                 finish();
56                 return true;
57             default:
58                 return super.onOptionsItemSelected(item);
59 
60         }
61     }
62 
63 
64 
65 
66 }
  • Liña 37: Recollemos o título do ítem pulsado.
  • Liñas 42,46,52,56: devolver true no caso de procesar cada un dos ítems.
  • Liña 58: Se non se procesou o ítem chamar ao pai, que vai devolver false por defecto.


  • Se na definición de cada ítem se houbera usado o atributo android:onClick entón teríamos que crear en java os métodos correspondentes do mesmo xeito que se fai cando se usa ese atributo nun Layout.

Menús contextuais

  • Pódense crear sobre calquera elemento View, pero normalmente vanse usar con ListView e GridView.*
  • Existen dúas formas de implantar este tipo de menús:
  • Menú contextual flotante:
  • O menú aparece cando o usuario prema durante un tempo longo un elemento e aparece unha lista.

Android 2014 U5 02 MenusContextuais 01.jpg


Para crear este tipo de menú:

  • O View que queira usalo ten que ser asociado ao mesmo chamando o método registerForContextMenu pasando o obxecto View.
  • Se todos os elementos do ListView / GridView teñen o mesmo menú contextual, se pode pasar como parámetro o ListView / GridView.
  • Por exemplo (isto se fai no método onCreate): registerForContextMenu(lista);
    • Sendo lista a referencia a unha ListView.



  • Implantar o método onCreateContextMenu() na Activity / Fragment.
    • Este método será chamado de forma automática cando o usuario preme durante un tempo o elemento (View) asociado o ContextMenu.
    • O que fai este método é amosar o menú contextual creado por nós previamente.
1 @Override
2 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
3     super.onCreateContextMenu(menu, v, menuInfo);
4     MenuInflater inflater = getMenuInflater();
5     inflater.inflate(R.menu.context_menu, menu);
6 }
  • Lembrar que o MenuInflater serve para pasar dun arquivo XML (o menú contextual definido por nós) a obxectos MenuItems.
  • Fixarse que un dos parámetros é o view sobre o que queremos amosar o menú contextual. Se temos varios rexistrados (registerForContextMenu) serviranos para saber de cal vimos.


  • Implantar o método onContextItemSelected() ao que se chama de forma automática cando se selecciona algo do menú contextual
 1         @Override
 2 	public boolean onContextItemSelected(MenuItem item) {
 3 		AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
 4 		switch (item.getItemId()) {
 5 		case R.id.edit:
 6 			// editNote(info.id); Lanzaríamos unha activity obtendo o texto do elemento da lista a partires do seu id ou coa súa posicición (info.position)
 7 			return true;
 8 		case R.id.delete:
 9 			// deleteNote(info.id); Borraríamos o elemento da lista en base ao seu id ou coa súa posicición (info.position)
10 			return true;
11 		default:
12 			return super.onContextItemSelected(item);
13 		}
14 	}
  • Liña 3. Do ítem pulsado recibimos información extra, entre outras, o "id" e a "posición" do ítem do adaptador sobre o que se pulsou durante un tempo para crear o menú contextual.
    • Ese "id" e "posición" son recollidos na variable info de tipo AdapterContextMenuInfo.
  • Liña 4: fixarse que é item.getItemId() para obter referencia ao id do menú contextual que foi seleccionado. Non confundir co id do elemento do adaptador sobre o que foi creado ese menú contextual.
  • O resto funciona igual que non menú básico.


  • Menú de modo acción contextual:
  • Neste caso, o menú aparece nunha barra de acción contextual na parte superior da pantalla (só dispoñible a partires da versión 3.0 API11).Android 2014 U5 02 MenusContextuais 02.jpg

Menú contextual: Caso Práctico aplicado a dous Views

Se non o temos creado antes, crearemos un novo paquete de nome: Menus como un subpaquete do teu paquete principal.



  • Dentro do paquete Menus crear unha nova 'Empty Activity' de nome: UD04_02_Menus de tipo Launcher e sen compatibilidade.
Modifica o arquivo AndroidManifiest.xml e engade unha label á activity como xa vimos na creación do proxecto base.



  • Neste exemplo imos asociar dous menús contextuais diferentes a dous views calquera. No exemplo serán dos ImageView, pero se podería empregar calquera View.


PDM menu emerx 1.jpg


  • O proceso que tedes que aprender é o seguinte:
  • Primeiro paso se deben crear o/s menús emerxentes que queiramos que aparezan (as opcións de menú)
  • Segundo paso se debe asociar un Context Menu a cada view. Para iso se ten que chamar ao método registerForContextMenu() e pasarlle como parámetro o view que queiramos que teña un Context Menu.
  • Terceiro paso se debe sobreescribir o método onCreateContextMenu(). A este método chegarán todos os views que estean rexistrados no paso anterior. É aquí onde temos que facer a operación de 'inflater' do menú asociado.
  • Cuarto paso se debe sobreescribir o método onContextItemSelected() onde chegará a execución ao premer sobre un dos menú items do menú emerxente.


  • Vexamos estes catro pasos aplicados ao noso exemplo:
Primeiro paso: Creamos os menús emerxentes que van aparecer. No exemplo creamos dous.

Arquivo: /res/menu/menu_context1_ud04_02_menus.xml

1 <?xml version="1.0" encoding="utf-8"?>
2 <menu xmlns:android="http://schemas.android.com/apk/res/android">
3 
4     <item
5         android:id="@+id/mniAdd_UD04_02_Menus"
6         android:title="Engadir" />
7 </menu>


Arquivo: /res/menu/menu_context2_ud04_02_menus.xml

1 <?xml version="1.0" encoding="utf-8"?>
2 <menu xmlns:android="http://schemas.android.com/apk/res/android">
3 
4     <item
5         android:id="@+id/mniDel_UD04_02_Menus"
6         android:title="Borrar" />
7 </menu>


Segundo Paso: Asociar un Context Menu a cada view.

Activity: UD04_02_Menus.java

 1 package cifprodolfoucha.cursoandroid.aprendiendo.UD4.Menus;
 2 
 3 import android.support.v7.app.AppCompatActivity;
 4 import android.os.Bundle;
 5 import android.view.ContextMenu;
 6 import android.view.MenuInflater;
 7 import android.view.MenuItem;
 8 import android.view.View;
 9 import android.widget.Toast;
10 
11 import cifprodolfoucha.cursoandroid.aprendiendo.R;
12 
13 public class UD04_02_Menus extends AppCompatActivity {
14 
15     private void asociarMenusContextual(){
16 
17         registerForContextMenu(findViewById(R.id.imvEstrela_UD04_02_Menus));
18         registerForContextMenu(findViewById(R.id.imvCrono_UD04_02_Menus));
19     }
20 
21 
22     @Override
23     protected void onCreate(Bundle savedInstanceState) {
24         super.onCreate(savedInstanceState);
25         setContentView(R.layout.activity_ud04_02__menus);
26 
27         asociarMenusContextual();
28     }
29 }


Terceiro Paso: Débese sobreescribir o método onCreateContextMenu()

Activity: UD04_02_Menus.java

 1     @Override
 2     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
 3         super.onCreateContextMenu(menu, v, menuInfo);
 4 
 5         MenuInflater inflater = getMenuInflater();
 6         switch(v.getId()) {
 7             case R.id.imvEstrela_UD04_02_Menus:
 8                 inflater.inflate(R.menu.menu_context1_04_02_menus,menu);
 9                 break;
10             case R.id.imvCrono_UD04_02_Menus:
11                 inflater.inflate(R.menu.menu_context2_04_02_menus,menu);
12                 break;
13         }
14     }
Línea 6: En función do view que que vai activar Menú Contextual,...
Línea 8,11: Cargamos un menú ou outro.


Cuarto Paso: Débese sobreescribir o método onContextItemSelected()

Activity: UD04_02_Menus.java

 1    @Override
 2     public boolean onContextItemSelected(MenuItem item) {
 3         switch(item.getItemId()) {
 4             case R.id.mniAdd_UD04_02_Menus:
 5                 Toast.makeText(this,"Pulsada a opción Engadir na imaxe 1",Toast.LENGTH_SHORT).show();
 6                 break;
 7             case R.id.mniDel_UD04_02_Menus:
 8                 Toast.makeText(this,"Pulsada a opción Borrar na imaxe 2",Toast.LENGTH_SHORT).show();
 9                 break;
10         }
11 
12 
13         return super.onContextItemSelected(item);
14     }
En función da opción escollida do menú contextual faremos unha acción concreta.


Menú popup: Caso Práctico aplicado a dous Views

  • Existe outra forma de 'emular' un menú emerxente e é empregando o evento LongClick a facendo aparercer un PopupMenu.


PDM menu emerx 2.jpg
Imos modificar o exercicio anterior e imos engadir unha nova imaxe, no que aparecerá o mesmo menú emerxente que empregamos na estrela.
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:app="http://schemas.android.com/apk/res-auto"
 4     xmlns:tools="http://schemas.android.com/tools"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent"
 7     tools:context=".UD4.Menus.UD04_02_Menus">
 8 
 9     <ImageView
10         android:id="@+id/imvEstrela_UD04_02_Menus"
11         android:layout_width="50dp"
12         android:layout_height="50dp"
13         android:layout_marginStart="8dp"
14         android:layout_marginTop="8dp"
15         android:contentDescription="Estrela"
16         app:layout_constraintStart_toStartOf="parent"
17         app:layout_constraintTop_toTopOf="parent"
18         app:srcCompat="@android:drawable/btn_star_big_on" />
19 
20     <ImageView
21         android:id="@+id/imvCrono_UD04_02_Menus"
22         android:layout_width="50dp"
23         android:layout_height="50dp"
24         android:layout_marginTop="8dp"
25         android:layout_marginEnd="8dp"
26         android:background="#10AC8C"
27         android:contentDescription="Reloxo"
28         app:layout_constraintEnd_toEndOf="parent"
29         app:layout_constraintTop_toTopOf="parent"
30         app:srcCompat="@android:drawable/ic_lock_idle_alarm" />
31 
32     <ImageView
33         android:id="@+id/imvCandado_UD04_02_Menus"
34         android:layout_width="50dp"
35         android:layout_height="50dp"
36         android:layout_marginStart="8dp"
37         android:layout_marginTop="8dp"
38         android:layout_marginEnd="8dp"
39         android:layout_marginBottom="8dp"
40         app:layout_constraintBottom_toBottomOf="parent"
41         app:layout_constraintEnd_toEndOf="parent"
42         app:layout_constraintStart_toStartOf="parent"
43         app:layout_constraintTop_toTopOf="parent"
44         app:srcCompat="@android:drawable/ic_lock_lock" />
45 </android.support.constraint.ConstraintLayout>


  • Agora imos modificar o código da Activity para que amose o PopUp. Lembrar que non creamos un menú novo xa que imos empregar o definido para a estrela.
O que temos que facer é capturar o evento LongClick sobre a imaxe e crear un obxecto da clase PopupMenu.

Activity UD04_02_Menus.java

 1 import android.support.v7.widget.PopupMenu;
 2 
 3    ................
 4     private void asociarMenuPopup(){
 5         findViewById(R.id.imvCandado_UD04_02_Menus).setOnLongClickListener(
 6                 new View.OnLongClickListener() {
 7                     @Override
 8                     public boolean onLongClick(View v) {
 9                         PopupMenu popupMenu = new PopupMenu(getApplicationContext(),v);
10                         popupMenu.inflate(R.menu.menu_context1_04_02_menus);
11                         popupMenu.show();
12 
13                         return true;
14                     }
15                 }
16         );
17     }
18 
19 
20     @Override
21     protected void onCreate(Bundle savedInstanceState) {
22         super.onCreate(savedInstanceState);
23         setContentView(R.layout.activity_ud04_02__menus);
24 
25         asociarMenusContextual();
26         asociarMenuPopup();
27     }
Para crear un obxecto PopupMenu debemos:
  • Instancialo (crear un obxecto da clase PopupMenu) pasando como parámetros ao constructor unha referencia ao contexto da activity e o view sobre o que se vai a xerar o popupmenu (no noso caso a imaxe): PopupMenu popupMenu = new PopupMenu(getApplicationContext(),v);
  • Inflar o menú chamando ao método inflate da instancia anterior e pasando como parámetro a referencia ao /res/menu/ que queiramos que apareza: popupMenu.inflate(R.menu.menu_context1_04_02_menus);
  • Chamar ao método show(): popupMenu.show();


  • Agora para xestionar os eventos de 'Click' sobre o PopupMenu, debemos facer uso do método setOnMenuItemClickListener() do PopupMenu.
Ao igual que calquera evento, dito método espera recibir un obxecto dunha clase que implementa a interface 'android.widget.PopupMenu.OnMenuItemClickListener'. Podemos facelo a nivel de Activity ou cunha clase anónima como calquera outro evento:

Activity UD04_02_Menus.java

 1     private void asociarMenuPopup(){
 2         findViewById(R.id.imvCandado_UD04_02_Menus).setOnLongClickListener(
 3                 new View.OnLongClickListener() {
 4                     @Override
 5                     public boolean onLongClick(View v) {
 6                         PopupMenu popupMenu = new PopupMenu(getApplicationContext(),v);
 7                         popupMenu.inflate(R.menu.menu_context1_04_02_menus);
 8                         popupMenu.show();
 9 
10                         popupMenu.setOnMenuItemClickListener(new android.widget.PopupMenu.OnMenuItemClickListener() {
11                             @Override
12                             public boolean onMenuItemClick(MenuItem menuItem) {
13                                 if (menuItem.getItemId()==R.id.mniAdd_UD04_02_Menus) {
14                                     Toast.makeText(getApplicationContext(), "Pulsado ",Toast.LENGTH_SHORT).show();
15                                     return true;
16                                 }
17                                 return false;
18                             }
19                         });
20 
21 
22                         return true;
23                     }
24                 }
25         );
26     }



Menú contextual: Caso Práctico aplicado a un RecyclerView

PDM menu emerx 3.jpg
  • Este sería un caso típico onde queremos que cando mantemos premido un elemento da lista, apareza un menú emerxente e poidamos escoller a opción 'Eliminar'.



Opción 1) Rexistrar un ContextMenu

  • O problema que imos ter é que onde se atopan os datos é na Activity, mentres que onde se atopan os compoñentes gráficos onde queremos asociar un ContextMenu se atopan no ViewHolder.


  • Segundo vimos anteriormente, para rexistrar un ContextMenu temos que chamar ao método registerForContextMenu() e pasarlle como parámetro cada elemento da lista.
Cada elemento da lista se atopa na clase ViewHolder creada por nos, concretamente no constructor:
 1 public class ViewHolder_UD04_01_RecycleViewCardView extends RecyclerView.ViewHolder {
 2 
 3     public ImageView itemImaxe;
 4     public TextView itemTexto;
 5 
 6     public ViewHolder_UD04_01_RecycleViewCardView(@NonNull final View itemView) {
 7         super(itemView);
 8 
 9         itemImaxe = itemView.findViewById(R.id.imgImaxe_UD04_01_CardLayout);
10         itemTexto = itemView.findViewById(R.id.tvTexto_UD04_01_CardView);
11 
12         ((UD04_01_RecycleViewCardView)itemView.getContext()).registerForContextMenu(itemView);
13         
14         itemView.setOnClickListener(new View.OnClickListener() {
15             @Override
16             public void onClick(View v) {
17                 Planeta_UD04_01_RecycleViewCardView planetaSeleccionado = (Planeta_UD04_01_RecycleViewCardView) v.getTag();
18 
19                 Toast.makeText(v.getContext(),"Pulsado elemento " + getAdapterPosition() + " da lista.\n" + planetaSeleccionado,Toast.LENGTH_SHORT).show();
20             }
21         });
22     }
23 }
O obxecto 'itemview' representa todos os views que conforman cada elemento da lista (no noso exemplo, a imaxe e o textview).
Non podemos chamar a registerContextView xa que dito método pertence a clase Activity, polo que é necesario obter unha referencia a dita clase.
O facemos a través da clase Context, xa que podemos obter unha referencia ao contexto a partires do 'itemview'.




  • Unha vez feito facemos como no exercicio anterior (estamos empregando o menú contextual feito no exercicio anterior, podedes crear un novo se queredes):

Activity UD04_01_RecycleViewCardView:

 1 package cifprodolfoucha.cursoandroid.aprendiendo.UD4.Adaptadores;
 2 
 3 import android.support.design.widget.FloatingActionButton;
 4 import android.support.v7.app.AppCompatActivity;
 5 import android.os.Bundle;
 6 import android.support.v7.widget.LinearLayoutManager;
 7 import android.support.v7.widget.RecyclerView;
 8 import android.view.ContextMenu;
 9 import android.view.MenuInflater;
10 import android.view.MenuItem;
11 import android.view.View;
12 import android.widget.Toast;
13 
14 import java.util.ArrayList;
15 
16 import cifprodolfoucha.cursoandroid.aprendiendo.R;
17 
18 public class UD04_01_RecycleViewCardView extends AppCompatActivity {
19 
20     private RecycleViewAdapter_UD04_01_RecycleViewCardView recycleAdapter;
21 
22     private ArrayList<Planeta_UD04_01_RecycleViewCardView>planetas;
23 
24 
25     @Override
26     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
27         super.onCreateContextMenu(menu, v, menuInfo);
28 
29         MenuInflater menuInflater = getMenuInflater();
30         menuInflater.inflate(R.menu.menu_context2_04_02_menus,menu);
31 
32     }
33 
34     @Override
35     public boolean onContextItemSelected(MenuItem item) {
36 
37         if (item.getItemId()==R.id.mniDel_UD04_02_Menus){
38             Toast.makeText(this,"Debemos eliminar este elemento de menú",Toast.LENGTH_SHORT).show();
39         }
40 
41         return super.onContextItemSelected(item);
42     }
43 
44     private void inicializarDatosPlanetas(){
45 
46         planetas = new ArrayList<>();
47 
48         planetas.add(new Planeta_UD04_01_RecycleViewCardView(1,"MERCURIO",false,R.drawable.mercurio));
49         planetas.add(new Planeta_UD04_01_RecycleViewCardView(2,"VENUS",false,R.drawable.venus));
50         planetas.add(new Planeta_UD04_01_RecycleViewCardView(3,"TIERRA",false,R.drawable.tierra));
51         planetas.add(new Planeta_UD04_01_RecycleViewCardView(4,"JUPITER",false,R.drawable.jupiter));
52         planetas.add(new Planeta_UD04_01_RecycleViewCardView(5,"SATURNO",false,R.drawable.saturno));
53 
54     }
55     private void inicializarRecycleView(){
56 
57         recycleAdapter = new RecycleViewAdapter_UD04_01_RecycleViewCardView(planetas);
58 
59         RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
60         RecyclerView recyclerView = findViewById(R.id.rvwRecycleView);
61         recyclerView.setLayoutManager(layoutManager);
62         recyclerView.setAdapter(recycleAdapter);
63 
64 
65     }
66 
67     private void xestionarEventos(){
68 
69         FloatingActionButton fab = findViewById(R.id.fabAdd_ud04_01_recyclecardview);
70         fab.setOnClickListener(new View.OnClickListener() {
71             @Override
72             public void onClick(View v) {
73                 planetas.add(new Planeta_UD04_01_RecycleViewCardView(6,"URANO",false,R.drawable.ic_menu_camera));
74                 recycleAdapter.notifyItemInserted(planetas.size());
75 
76             }
77         });
78 
79     }
80 
81 
82     @Override
83     protected void onCreate(Bundle savedInstanceState) {
84         super.onCreate(savedInstanceState);
85         setContentView(R.layout.activity_ud04_01__recycle_view_card_view);
86 
87         inicializarDatosPlanetas();
88         inicializarRecycleView();
89         xestionarEventos();
90 
91     }
92 }
  • Agora o problema é saber que elemento da lista necesitamos borrar.
Ao método 'onContextItemSelected()' chega o elemento de menú seleccionado, pero nada acerca do elemento da lista.
Podemos aproveitar que o ItemView seleccionado chega ao método onCreateContextMenu() e recoller aí cal é o view sobre o que estamos a xerar o menú contextual.
Xa vimos no ImageView e tamén no RecyclerView como asociar información a un view: Empregando a propiedade Tag.
O tag xa o temos 'collido' e gardamos nel o obxecto planeta do exercicio feito no punto RecyclerView-CardView:

Arquivo: RecycleViewAdapter_UD04_01_RecycleViewCardView

1     @Override
2     public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
3 
4         ViewHolder_UD04_01_RecycleViewCardView viewHolderMeu = (ViewHolder_UD04_01_RecycleViewCardView) viewHolder;
5 
6         viewHolderMeu.itemView.setTag(planetas.get(i));
7         viewHolderMeu.itemImaxe.setImageResource(planetas.get(i).getFotoId());
8         viewHolderMeu.itemTexto.setText(planetas.get(i).getNome());
9     }


Podemos por tanto gardar esta información na activity para despois ser empregada no método onContextItemSelected():

Arquivo: UD04_01_RecycleViewCardView

 1 .............
 2 public class UD04_01_RecycleViewCardView extends AppCompatActivity {
 3 
 4     private RecycleViewAdapter_UD04_01_RecycleViewCardView recycleAdapter;
 5 
 6     private ArrayList<Planeta_UD04_01_RecycleViewCardView>planetas;
 7     private Planeta_UD04_01_RecycleViewCardView planetaSeleccionado;
 8 
 9 
10     @Override
11     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
12         super.onCreateContextMenu(menu, v, menuInfo);
13 
14         MenuInflater menuInflater = getMenuInflater();
15         menuInflater.inflate(R.menu.menu_context2_04_02_menus,menu);
16 
17         planetaSeleccionado = (Planeta_UD04_01_RecycleViewCardView)  v.getTag();
18 
19     }
20 
21     @Override
22     public boolean onContextItemSelected(MenuItem item) {
23 
24         if (item.getItemId()==R.id.mniDel_UD04_02_Menus){
25             Toast.makeText(this,"Debemos eliminar este elemento de menú " + planetaSeleccionado,Toast.LENGTH_SHORT).show();
26             planetas.remove(planetaSeleccionado);
27             recycleAdapter.notifyDataSetChanged();
28         }
29 
30         return super.onContextItemSelected(item);
31     }
32     ..............
  • Liña 27: Fixarse que temos que chamar a notifyDataSetChanged() xa que non sabemos cal é o índice do elemento seleccionado.


  • Podemos 'optimizar' e facer que soamente 'actualice' a lista sobre o elemento borrado:

Arquivo: UD04_01_RecycleViewCardView

 1      .............
 2 public class UD04_01_RecycleViewCardView extends AppCompatActivity {
 3 
 4     private RecycleViewAdapter_UD04_01_RecycleViewCardView recycleAdapter;
 5 
 6     private ArrayList<Planeta_UD04_01_RecycleViewCardView>planetas;
 7     private Planeta_UD04_01_RecycleViewCardView planetaSeleccionado;
 8 
 9 
10     @Override
11     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
12         super.onCreateContextMenu(menu, v, menuInfo);
13 
14         MenuInflater menuInflater = getMenuInflater();
15         menuInflater.inflate(R.menu.menu_context2_04_02_menus,menu);
16 
17         planetaSeleccionado = (Planeta_UD04_01_RecycleViewCardView )v.getTag();
18 
19     }
20 
21     @Override
22     public boolean onContextItemSelected(MenuItem item) {
23 
24         if (item.getItemId()==R.id.mniDel_UD04_02_Menus){
25             Toast.makeText(this,"Debemos eliminar este elemento de menú " + planetaSeleccionado,Toast.LENGTH_SHORT).show();
26             int indicePlaneta = planetas.indexOf(planetaSeleccionado);
27             planetas.remove(planetaSeleccionado);
28             recycleAdapter.notifyItemRemoved(indicePlaneta);
29         }
30 
31         return super.onContextItemSelected(item);
32     }
33     ...............



Opción 2) Empregar un PopupMenu

  • Serás capaz de facelo ?
Como pista comentar que teredes que rexistrar a interface OnLongClickListener no itemView do ViewHolder, pero teredes que informarlle que dita interface esté implementada na Activity.
Implementar a interface na Activity e seguir coma no exemplo anterior do PopupMenu.



Menú contextual: Caso Práctico aplicado a unha ListView e un TextView

Se non o temos creado antes, crearemos un novo paquete de nome: Menus como un subpaquete do teu paquete principal.



  • Dentro do paquete Menus crear unha nova 'Empty Activity' de nome: UD04_02_Menus de tipo Launcher e sen compatibilidade.
Modifica o arquivo AndroidManifiest.xml e engade unha label á activity como xa vimos na creación do proxecto base.



  • Neste caso vanse crear dous menús contextuais distintos:
    • un para unha etiqueta (TextView)
    • e outro para unha lista (ListView).

Menú contextual: O XML do Layout

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:app="http://schemas.android.com/apk/res-auto"
 4     xmlns:tools="http://schemas.android.com/tools"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent"
 7     tools:context=".Menus.UD04_02_Menus">
 8 
 9     <TextView
10         android:id="@+id/tvTexto_UD04_02_Menus"
11         android:layout_width="wrap_content"
12         android:layout_height="wrap_content"
13         android:layout_marginEnd="8dp"
14         android:layout_marginStart="8dp"
15         android:layout_marginTop="8dp"
16         android:text="Hello World"
17         android:textSize="18sp"
18         app:layout_constraintEnd_toEndOf="parent"
19         app:layout_constraintStart_toStartOf="parent"
20         app:layout_constraintTop_toTopOf="parent" />
21 
22     <ListView
23         android:id="@+id/lvFroitas_UD04_02_Menus"
24         android:layout_width="0dp"
25         android:layout_height="169dp"
26         android:layout_marginEnd="8dp"
27         android:layout_marginStart="8dp"
28         android:layout_marginTop="16dp"
29         app:layout_constraintEnd_toEndOf="parent"
30         app:layout_constraintHorizontal_bias="1.0"
31         app:layout_constraintStart_toStartOf="parent"
32         app:layout_constraintTop_toBottomOf="@+id/tvTexto_UD04_02_Menus" />
33 </android.support.constraint.ConstraintLayout>

Menú contextual: O XML dos menús contextuais

  • Imos crear dous recursos xml para cada un dos menús contextuais distintos que temos segundo premamos sobre un TextView ou sobre un ListView.
  • Poderían ser o mesmo menú contextual, pero así aprendemos que estes poden ser distintos en función da View ao que se asocien.

PDM MenusContextuais 10.jpg



  • O xml de /res/menu/menu_ud04_02_context_etiqueta.xml
Nota: O Android Studio seguramente vos dirá que existe un erro na liña android:showAsAction e que deberedes cambialo por 'app:showAsAction'. Ese aviso aparece debido a que tedes importado a librería de compatibilidade v7 nalgunha outra práctica. Soamente sería necesario se a activity derivase da clase AppCompactActivity como fixemos na práctica anterior (deberedes de aplicalo ao voso caso).


 1 <?xml version="1.0" encoding="utf-8"?>
 2 <menu xmlns:android="http://schemas.android.com/apk/res/android">
 3 
 4     <item
 5         android:id="@+id/mniItem1_04_02_context_etiq"
 6         android:showAsAction="withText"
 7         android:title="TextView opción 1">
 8     </item>
 9     <item
10         android:id="@+id/mniItem2_04_02_context_etiq"
11         android:showAsAction="withText"
12         android:title="TextView opción 2">
13     </item>
14 
15 </menu>


  • O xml de /res/menu/menu_ud04_02_context_lista.xml
Nota: O Android Studio seguramente vos dirá que existe un erro na liña android:showAsAction e que deberedes cambialo por 'app:showAsAction'. Non lle fagades caso Ese aviso aparece debido a que tedes importado a librería de compatibilidade v7 nalgunha outra práctica. Soamente sería necesario se a activity derivase da clase AppCompactActivity como fixemos na práctica anterior.
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <menu xmlns:android="http://schemas.android.com/apk/res/android" >
 3 
 4     <item
 5         android:id="@+id/mniItemBorrar_ud04_02_context_lista"
 6         android:showAsAction="withText"
 7         android:title="Borrar">
 8     </item>
 9     <item
10         android:id="@+id/mniItemDuplicar_ud04_02_context_lista"
11         android:showAsAction="withText"
12         android:title="Duplicar">
13     </item>
14 </menu>


  • Observar que nos dous ficheiros xml cada item ten asociado un "id", para logo ser identificado o ítem cando sexa procesado no código.

Menú contextual: o código Java da aplicación

  1 package es.cursoandroid.cifprodolfoucha.aprendiendo.Menus;
  2 
  3 import android.app.Activity;
  4 import android.os.Bundle;
  5 import android.view.ContextMenu;
  6 import android.view.MenuInflater;
  7 import android.view.MenuItem;
  8 import android.view.View;
  9 import android.widget.AdapterView;
 10 import android.widget.ArrayAdapter;
 11 import android.widget.ListView;
 12 import android.widget.TextView;
 13 import android.widget.Toast;
 14 
 15 import java.util.ArrayList;
 16 import java.util.Arrays;
 17 
 18 import es.cursoandroid.cifprodolfoucha.aprendiendo.R;
 19 
 20 public class UD04_02_Menus extends Activity {
 21 
 22 
 23     private void rexistarMenusEmerxentes(){
 24 
 25         TextView tv = findViewById(R.id.tvTexto_UD04_02_Menus);
 26         registerForContextMenu(tv);
 27 
 28         ListView lv = findViewById(R.id.lvFroitas_UD04_02_Menus);
 29         registerForContextMenu(lv);
 30     }
 31 
 32     private void engadirDatosLista(){
 33         String[] froitas = new String[] { "Laranxa", "Mango", "Ameixa" };
 34         ArrayList<String> alFroitas = new ArrayList<String>();
 35 
 36         alFroitas.addAll(Arrays.asList(froitas));
 37 
 38         ArrayAdapter<String> adaptador = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, alFroitas);
 39         adaptador.setDropDownViewResource(android.R.layout.simple_list_item_1);
 40 
 41         ListView lv = findViewById(R.id.lvFroitas_UD04_02_Menus);
 42         lv.setAdapter(adaptador);
 43 
 44     }
 45 
 46     @Override
 47     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
 48         super.onCreateContextMenu(menu, v, menuInfo);
 49         MenuInflater inflater = getMenuInflater();
 50 
 51         // Comprobamos se o menú contextual se lanzou sobre a etiqueta ou sobre
 52         // a lista
 53         if (v.getId() == R.id.tvTexto_UD04_02_Menus) {
 54             inflater.inflate(R.menu.menu_ud04_02_context_etiqueta, menu);
 55         }
 56 
 57         else if (v.getId() == R.id.lvFroitas_UD04_02_Menus) {
 58             inflater.inflate(R.menu.menu_ud04_02_context_lista, menu);
 59         }
 60     }
 61 
 62     @Override
 63     public boolean onContextItemSelected(MenuItem item) {
 64         AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
 65         
 66         ListView lv = findViewById(R.id.lvFroitas_UD04_02_Menus);
 67         ArrayAdapter<String> adaptador = (ArrayAdapter<String>) lv.getAdapter();
 68 
 69         switch (item.getItemId()) {
 70 
 71             // Ítems premidos sobre o TextView
 72             // Lanza un Toast coa opción do menú contextual que se seleccinou
 73             case R.id.mniItem1_04_02_context_etiq:
 74                 Toast.makeText(this, "Menú contextual TextView:\n"+item.getTitle(), Toast.LENGTH_SHORT).show();
 75                 return true;
 76 
 77             case R.id.mniItem2_04_02_context_etiq:
 78                 Toast.makeText(this, "Menú contextual TextView:\n"+item.getTitle(), Toast.LENGTH_SHORT).show();
 79                 return true;
 80 
 81             // Ítems premidos sobre o ListView
 82             case R.id.mniItemBorrar_ud04_02_context_lista:
 83                 adaptador.remove(adaptador.getItem(info.position));
 84                 adaptador.setNotifyOnChange(true);
 85                 return true;
 86 
 87             case R.id.mniItemDuplicar_ud04_02_context_lista:
 88                 adaptador.add(adaptador.getItem(info.position));
 89                 adaptador.setNotifyOnChange(true);
 90 
 91                 return true;
 92             default:
 93                 return super.onContextItemSelected(item);
 94         }
 95     }
 96 
 97     @Override
 98     protected void onCreate(Bundle savedInstanceState) {
 99         super.onCreate(savedInstanceState);
100         setContentView(R.layout.activity_ud04_02__menus);
101 
102         rexistarMenusEmerxentes();
103         engadirDatosLista();
104     }
105 
106 
107 }
  • Liña 26: indicamos que TextView vai ter un menú contextual asociado.
  • Liña 29: indica que o ListView de froitas vai ter un menú contextual asociado.
  • Liñas 33,34: Creamos un Array estático que logo asignamos a un dinámico.
  • Liña 36: usamos o array dinámico para logo en tempo de execución poder engadir/borrar elementos do adaptador e por tanto do ListView.
Nota: Se poñemos un array como parámetro no ArrayAdapter, non poderíamos facer operacións de borrado e engadir novos elementos.


  • Liñas 46-60: onCreateContexMenu() vai ser chamado cando se prema durante un anaco sobre unha view, neste caso comprobamos sobre que view se premeu e lánzase ("inflase") o correspondente menú contextual, cada un deles definido nun ficheiro xml distinto.


  • Liñas 62-95: En función do id do ítem premido realizamos unhas accións ou outras como no caso dos menús básicos. Só que neste caso os ids proveñen de ítems de menús declarados en 2 ficheiros distintos.



Personalizar título do menú contextual

  • Se queremos que o menú contextual teña un título debemos usar o método: setHeaderTitle()
  • As seguintes imaxes amosan un exemplo para o caso do TextView e o ListView:


  • Os cambios a realizar no código Java son os seguintes:
  • No memento no que hai que crear o menú contextual:
 1     @Override
 2     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
 3         super.onCreateContextMenu(menu, v, menuInfo);
 4         MenuInflater inflater = getMenuInflater();
 5 
 6         // Comprobamos se o menú contextual se lanzou sobre a etiqueta ou sobre
 7         // a lista
 8         if (v.getId() == R.id.tvTexto_UD04_02_Menus) {
 9             menu.setHeaderTitle("Etiqueta de texto");
10             inflater.inflate(R.menu.menu_ud04_02_context_etiqueta, menu);
11         }
12         else if (v.getId() == R.id.lvFroitas_UD04_02_Menus) {
13             AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
14 
15             ListView lv = findViewById(R.id.lvFroitas_UD04_02_Menus);
16             menu.setHeaderTitle(lv.getAdapter().getItem(info.position).toString());
17             inflater.inflate(R.menu.menu_ud04_02_context_lista, menu);
18         }
19     }
  • Liñas 9,16: establecemos o título para o menú contextual.




Enlace a la página principal de la UD6

Enlace a la página principal del curso



-- Ángel D. Fernández González e Carlos Carrión Álvarez -- (2015).