Spinner a través de adaptador

De MediaWiki
Saltar a: navegación, buscar

Introdución


  • Xa vimos na unidade 2 como crear un Spinner, pero o enlace dos datos co Spinner facíase a través dun atributo XML na definición do Spinner no Layout: android:entries.
  • Agora imos facer o mesmo pero usando un adaptador.
  • Colleremos os datos dende un array no código e logo dende un recurso XML.


  • Se queremos cargar ditos recursos por programación:
  • Deberemos facer uso dun obxecto da clase ArrayAdapter. Este obxecto serve coma ponte entre os datos e o spinner. A modificacións dos datos da lista sempre se fai no adaptador asociado á mesma e nunca sobre o spinner. Engadir, borrar, modificar, limpar,...todas esas operacións se teñen que facer sobre o adaptador.
  • Deberemos de obter os datos para encher o spinner. Estes datos poden vir dun array gardado en /res/ e para referencialo teremos que facer uso do método getResources().
  • Deberemos de establecer o aspecto (layout) que terá cada un dos 'views' que conforman cada elemento da lista (si, cada elemento da lista ten que ser un view :) )
  • Deberemos establecer o aspecto (layout) de cada elemento do spinner cando prememos na lista e se despregan todos eles.


  • Para crear un ArrayAdapter podemos seguir este código:
  1.         Spinner lista = findViewById(R.id.id_spinner);
  2.  
  3.         ArrayAdapter<CharSequence>adaptador = ArrayAdapter.createFromResource(this,R.array.planetas_UD02_01_spinner,android.R.layout.simple_list_item_1);
  4.         adaptador.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
  5.         lista.setAdapter(adaptador);


  • O contexto
  • Os datos do ArrayAdapter, que neste caso veñen dun recurso xa creado previamente noutro exercicio.
  • O Layout que vai ter asociado cada view (elemento da lista, que dependendo do layout serán views como TextViews).
Os layout que se poden empregar se poden consultar en http://wiki.cifprodolfoucha.es/index.php?title=Spinner#Caso_pr.C3.A1ctico
O código fonte de cada layout se pode consultar en https://github.com/aosp-mirror/platform_frameworks_base/tree/master/core/res/res/layout


  • Na liña 4, establecemos o layout que vai ter o spinner cando prememos sobre el e aparezan todos os elementos da lista. Podemos consultar o código fonte de dito layout.
  • Na liña 5 asociamos o ArrayAdapter ao Spinner.




  • Podemos facer o mesmo desta outra forma:
  1. ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item,getResources().getStringArray(R.array.planetas_UD02_01_spinner));
Para referenciar o array teríamos que facer uso da clase getResource() e obter o tipo correspondente (array).


  • O ArrayAdapter está 'cheo' de métodos para engadir, borrar e modificar elementos da lista.
Por exemplo:
  • Importante: Calquera modificación que se faga sobre os elementos da lista facendo uso do adaptador, leva consigo a 'obriga' de informar ao view dos cambios para que os reflicta. Isto se consigo chamando ao método setNotifyOnChange(boolean notifyOnChange), cun valor true no parámetro.


  • Por exemplo, o código anterior se podería cambiar por:
  1. ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item);
  2. adapter.addAll(getResources().getStringArray(R.array.planetas_UD02_01_spinner));
  3. adapter.setNotifyOnChange(true);



Ao facelo, deberá implementarse estes dous método:
  1.             @Override
  2.             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
  3.  
  4.             }
  5.  
  6.             @Override
  7.             public void onNothingSelected(AdapterView<?> parent) {
  8.  
  9.             }
O segundo método se chama cando non se selecciona ningún elemento e desaparece a lista.
O primeiro cando se selecciona un elemento da lista.
Leva como parámetros:
  • O adaptador asociado á lista.
  • O view que foi seleccionado (lembrar que cando se crea o adaptador se establece un layout para cada compoñente da lista)
  • A posición do elemento seleccionado na lista (empeza en 0)
  • Un identificador para a fila que foi seleccionada.

Caso práctico 1

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



  • Dentro do paquete Adaptadores crear unha nova 'Empty Activity' de nome: UD04_01_Spinners 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.




  • Cada ítem do Spinner é tratado como unha View, neste caso de tipo TextView.

O XML do layout

  • Observar como a vista Spinner non ten a entrada android:entries.
  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=".Adaptadores.UD04_01_Spinners">
  8.  
  9.     <Spinner
  10.         android:id="@+id/spnLista_UD02_02_spinner"
  11.         android:layout_width="0dp"
  12.         android:layout_height="wrap_content"
  13.         android:layout_marginEnd="8dp"
  14.         android:layout_marginStart="8dp"
  15.         android:layout_marginTop="8dp"
  16.         android:dropDownWidth="match_parent"
  17.         app:layout_constraintEnd_toEndOf="parent"
  18.         app:layout_constraintStart_toStartOf="parent"
  19.         app:layout_constraintTop_toTopOf="parent" />
  20. </android.support.constraint.ConstraintLayout>


  • Partimos do exercicio de spinner feito anteriormente, no que está definido un array de datos, nun arquivo de /res/values:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3.  
  4.     <string-array name="planetas_UD02_01_spinner">
  5.         <item>Mercurio</item>
  6.         <item>Venus</item>
  7.         <item>Terra</item>
  8.         <item>Marte</item>
  9.         <item>Xúpiter</item>
  10.         <item>Saturno</item>
  11.         <item>Urano</item>
  12.         <item>Neptuno</item>
  13.     </string-array>
  14.  
  15. </resources>


  • O código da Activity:
  1. package es.cursoandroid.cifprodolfoucha.aprendiendo.Adaptadores;
  2.  
  3. import android.app.Activity;
  4. import android.os.Bundle;
  5. import android.view.View;
  6. import android.widget.AdapterView;
  7. import android.widget.ArrayAdapter;
  8. import android.widget.Spinner;
  9. import android.widget.TextView;
  10. import android.widget.Toast;
  11.  
  12. import es.cursoandroid.cifprodolfoucha.aprendiendo.R;
  13.  
  14. public class UD04_01_Spinners extends Activity {
  15.  
  16.     private void cargarLista() {
  17.  
  18.         Spinner lista = findViewById(R.id.spnLista_UD02_02_spinner);
  19.  
  20.         ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1);
  21.         adapter.addAll(getResources().getStringArray(R.array.planetas_UD02_01_spinner));
  22.         lista.setAdapter(adapter);
  23.  
  24.         lista.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
  25.             @Override
  26.             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
  27.                 //String datoLista = (String)parent.getItemAtPosition(position);    // Poderíamos obter o dato desta forma (fixarse no Cast)
  28.                 String datoLista = ((TextView) view).getText().toString();          // ou desta outra forma
  29.                 Toast.makeText(getApplicationContext(),"Elemento seleccionado:" + datoLista + " na posición "+ String.valueOf(position),Toast.LENGTH_LONG).show();
  30.             }
  31.  
  32.             @Override
  33.             public void onNothingSelected(AdapterView<?> parent) {
  34.  
  35.             }
  36.         });
  37.  
  38.     }
  39.     @Override
  40.     protected void onCreate(Bundle savedInstanceState) {
  41.         super.onCreate(savedInstanceState);
  42.         setContentView(R.layout.activity_ud04_01__spinners);
  43.  
  44.         cargarLista();
  45.  
  46.     }
  47. }
  • Liñas 20-22: Usamos unha das formas vistas para crear o adaptador e asocialo ao spinner.
  • Liña 24: Rexistramos a interface que xestiona o evento de selección dun elemento da lista.
  • Liñas 26-30: Facemos uso do método onItemSelected() e os seus parámetros para obter o dato da lista seleccionado.

Caso práctico 2: Usando un array estático en Java

  • Dentro do paquete Adaptadores crear unha nova 'Empty Activity' de nome: UD04_02_Spinners 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 cargaremos a fonte de datos dun array local.
PDM adaptador 3.jpg



O código XML da activity é:

  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=".Adaptadores.UD04_02_Spinners">
  8.  
  9.     <Spinner
  10.        android:id="@+id/spnLista_UD04_02_Spinner"
  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.        app:layout_constraintBottom_toBottomOf="parent"
  18.        app:layout_constraintEnd_toEndOf="parent"
  19.        app:layout_constraintStart_toStartOf="parent"
  20.        app:layout_constraintTop_toTopOf="parent" />
  21. </android.support.constraint.ConstraintLayout>



  • Ao final do código explícase como se enlaza a fonte de datos co adaptador e este co spinner.
  • Observar as liñas marcadas.
  1. package es.cursoandroid.cifprodolfoucha.aprendiendo.Adaptadores;
  2.  
  3. import android.app.Activity;
  4. import android.os.Bundle;
  5. import android.view.View;
  6. import android.widget.AdapterView;
  7. import android.widget.ArrayAdapter;
  8. import android.widget.Spinner;
  9. import android.widget.TextView;
  10. import android.widget.Toast;
  11.  
  12. import es.cursoandroid.cifprodolfoucha.aprendiendo.R;
  13.  
  14. public class UD04_02_Spinners extends Activity {
  15.  
  16.     private void cargarLista(){
  17.  
  18.             Spinner spinFroitas = (Spinner) findViewById(R.id.spnLista_UD04_02_Spinner);
  19.  
  20.             // Fonte de datos
  21.             String[] froitas = new String[] { "Pera", "Mazá", "Plátano" };
  22.  
  23.             // Enlace do adaptador cos datos
  24.             ArrayAdapter<String> adaptador = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, froitas);
  25.  
  26.             // Opcional: layout usuado para representar os datos no Spinner
  27.             adaptador.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
  28.  
  29.             // Enlace do adaptador co Spinner do Layout.
  30.             spinFroitas.setAdapter(adaptador);
  31.  
  32.             // Escoitador
  33.             spinFroitas.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
  34.                 @Override
  35.                 public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
  36.                     //Toast.makeText(getBaseContext(), "Seleccionaches: " + parent.getItemAtPosition(pos), Toast.LENGTH_LONG).show();
  37.                     Toast.makeText(getBaseContext(), "Seleccionaches: " + ((TextView) view).getText(), Toast.LENGTH_LONG).show();
  38.  
  39.                 }
  40.  
  41.                 @Override
  42.                 public void onNothingSelected(AdapterView<?> arg0) {
  43.                     // TODO Auto-generated method stub
  44.                 }
  45.             }); // Fin da clase anónima
  46.  
  47.     }
  48.  
  49.  
  50.     @Override
  51.     protected void onCreate(Bundle savedInstanceState) {
  52.         super.onCreate(savedInstanceState);
  53.         setContentView(R.layout.activity_ud04_02__spinners);
  54.  
  55.         cargarLista();
  56.     }
  57. }
  • Liña 23: Definimos a fonte de datos, neste caso un array estático.
  • Liña 26: Definimos o adaptador de tipo ArrayAdapter. Pasámoslle como parámetros:
    • Contexto,
    • O int, identificador de recurso de layout que se vai usar para representar a Vista de Selección, neste caso usamos un predefinido. O usuario pode experimentar con outros tipos (android.R.layout.... CTRL+ESPAZO) e ver que outras formas hai de presentar os datos nun Spinner.
    • Un array de obxectos, neste caso de Strings.
    • Para ver outros construtores e métodos: http://developer.android.com/reference/android/widget/ArrayAdapter.html
  • Liña 29: setDropDownViewResource(int), indica como se vai representar cada un dos ítems do Spinner. Usamos un layout xa predefinido. O usuario pode experimentar usando outros distintos, predefinidos ou propios.
  • Liña 32: establece o adaptador que subministra os datos ao Spinner.
  • Liña 35: O escoitador é o mesmo que cando non se usaba un adaptador.
  • Liñas 38,39: As dúas liñas fan o mesmo, pero no segundo caso observar como recollemos a vista (view) que nos devolve o evento ao premer nun ítem do Spinner. Esa view é do tipo TextView e por iso facemos un cast e logo xa lle podemos aplicar métodos da clase TextView, como getText().

Caso práctico 3: Uso dun array dinámico

  • Dentro do paquete Adaptadores crear unha nova 'Empty Activity' de nome: UD04_03_Spinners 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 cargaremos a fonte de datos dun array ArrayList. Cando vexamos o acceso a base de datos, os datos virán dunha táboa.
PDM adaptador 4.jpg



O código XML da activity é:

  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=".Adaptadores.UD04_02_Spinners">
  8.  
  9.     <Spinner
  10.        android:id="@+id/spnLista_UD04_03_Spinner"
  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.        app:layout_constraintBottom_toBottomOf="parent"
  18.        app:layout_constraintEnd_toEndOf="parent"
  19.        app:layout_constraintStart_toStartOf="parent"
  20.        app:layout_constraintTop_toTopOf="parent" />
  21. </android.support.constraint.ConstraintLayout>


  • Nos dous casos anteriores o contido do Spinner é estático e defínese en tempo de compilación, non de execución.
  • Se usamos arrays dinámicos podemos crear a fonte de datos en tempo de execución antes de pasarlla ao adaptador.
  • Así imos poder usar datos de ficheiros, bases de datos, etc e crear unha fonte de datos para un Spinner en tempo de execución.
  1. package es.cursoandroid.cifprodolfoucha.aprendiendo.Adaptadores;
  2.  
  3. import android.app.Activity;
  4. import android.os.Bundle;
  5. import android.view.View;
  6. import android.widget.AdapterView;
  7. import android.widget.ArrayAdapter;
  8. import android.widget.Spinner;
  9. import android.widget.TextView;
  10. import android.widget.Toast;
  11.  
  12. import java.util.ArrayList;
  13.  
  14. import es.cursoandroid.cifprodolfoucha.aprendiendo.R;
  15.  
  16. public class UD04_03_Spinners extends Activity {
  17.  
  18.     private void cargarLista(){
  19.  
  20.         Spinner spinFroitas = (Spinner) findViewById(R.id.spnLista_UD04_03_Spinner);
  21.  
  22.         ArrayList<String> animais = new ArrayList<String>();
  23.  
  24.         animais.add("CABALLOS");
  25.         animais.add("GATITOS");
  26.         animais.add("PERROS");
  27.         animais.add("RATONES");
  28.  
  29.         // Enlace do adaptador cos datos
  30.         ArrayAdapter<String> adaptador = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, animais);
  31.  
  32.         // Enlace do adaptador co Spinner do Layout.
  33.         spinFroitas.setAdapter(adaptador);
  34.  
  35.         // Escoitador
  36.         spinFroitas.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
  37.             @Override
  38.             public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
  39.                 //Toast.makeText(getBaseContext(), "Seleccionaches: " + parent.getItemAtPosition(pos), Toast.LENGTH_LONG).show();
  40.                 Toast.makeText(getBaseContext(), "Seleccionaches: " + ((TextView) view).getText(), Toast.LENGTH_LONG).show();
  41.  
  42.             }
  43.  
  44.             @Override
  45.             public void onNothingSelected(AdapterView<?> arg0) {
  46.                 // TODO Auto-generated method stub
  47.             }
  48.         }); // Fin da clase anónima
  49.  
  50.     }
  51.  
  52.  
  53.     @Override
  54.     protected void onCreate(Bundle savedInstanceState) {
  55.         super.onCreate(savedInstanceState);
  56.         setContentView(R.layout.activity_ud04_03__spinners);
  57.  
  58.         cargarLista();
  59.     }
  60. }
  • Liñas 23-28: Neste caso os elementos do array engádense en tempo de execución ao array animais, que neste caso e do tipo ArrayList.
  • O resto é exactamente igual.



Caso práctico 4: Personalizando o deseño

  • Dentro do paquete Adaptadores crear unha nova 'Empty Activity' de nome: UD04_04_Spinners 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.



  • Como indicamos dende o inicio, cando creamos o Spinner tamén creamos un adaptador sobre o cal indicamos o layout de cada compoñente da lista.
Podemos crear nos mesmos o deseño que queiramos cos datos que queiramos que aparezan na lista.
  • Para facer o anterior, temos que crear o noso propio adaptador.
  • Nesta práctica creamos un layout formado por unha imaxe e un texto para cada elemento da lista do spinner.
PDM adaptador 10.jpg



  • Como o que queremos é facer un deseño específico para cada 'fila' de elementos da lista / spinner, imos crear o Layout que vai representar cada fila:

Nome Arquivo do layout: spinner_ud04_04.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.    xmlns:app="http://schemas.android.com/apk/res-auto"
  4.    android:layout_width="match_parent"
  5.    android:layout_height="match_parent">
  6.  
  7.     <ImageView
  8.        android:id="@+id/imgVImaxen_UD04_04_Spinners"
  9.        android:layout_width="wrap_content"
  10.        android:layout_height="wrap_content"
  11.        android:layout_weight="1"
  12.         />
  13.  
  14.     <TextView
  15.        android:id="@+id/txtTexto_UD04_04_Spinners"
  16.        android:layout_width="wrap_content"
  17.        android:layout_height="wrap_content"
  18.        android:layout_weight="2"
  19.        android:text="TextView" />
  20. </LinearLayout>
Como vemos, estamos a definir un layout cun Imageview e un TextView. Pero poderíamos poñer calquera lauyout con calquera número de elementos e deseño.


Partimos dun exercicio anterior onte xa tiñamos definidos nun array os datos do exercicio:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3.  
  4.     <string-array name="planetas_UD02_01_spinner">
  5.         <item>Mercurio</item>
  6.         <item>Venus</item>
  7.         <item>Terra</item>
  8.         <item>Marte</item>
  9.         <item>Xúpiter</item>
  10.         <item>Saturno</item>
  11.         <item>Urano</item>
  12.         <item>Neptuno</item>
  13.     </string-array>
  14.  
  15. </resources>



  • Agora crearemos o Adaptador.
Despois de facer o anterior teremos un código coma isto:
Arquivo: Adaptador_UD04_04_Spinners
  1. public class Adaptador_UD04_04_Spinners extends ArrayAdapter {
  2.    
  3.     public AdaptadorPrueba(@NonNull Context context, int resource) {
  4.         super(context, resource);
  5.     }
  6. }


  • Agora debemos ter claro que o que imos a 'enviar' a este adaptador van ser os datos necesarios para que 'constrúa' a lista de elementos.
No noso caso, queremos que faga unha lista de elementos no que cada elemento vai ser un texto (TextView) e unha imaxe (ImageView).
Polo tanto teremos que enviar un array de cadeas (para o texto) e algo para facer unha imaxe. No exemplo imos a enviarlle imaxes gardadas en /res/drawable/ e polo tanto serán un array de enteiros (lembrar que en /res/ todo se referencia por números facendo uso da clase R). Poderíamos enviar URL e que o ImageView cargase a imaxe de dita URL.
Modificamos o construtor para que recolla estes datos. Como teremos que facer uso deles noutros métodos, crearemos propiedades locais na clase:
  1. public class Adaptador_UD04_04_Spinners extends ArrayAdapter {
  2.  
  3.     int[] imaxes;   // Lista de imaxes a cargar. Lembra que en res todo son números  Se foran url poderíamos cambialo por String[]
  4.     String[] textos;
  5.     Context mContext;
  6.  
  7.     public Adaptador_UD04_04_Spinners(@NonNull Context context, int[]imaxes,String[]textos) {
  8.         super(context, R.layout.spinner_ud04_04);       // Enviamos o layout que imos utilizar
  9.  
  10.         this.imaxes = imaxes;
  11.         this.textos = textos;
  12.         this.mContext = context;
  13.     }
  14.    
  15. }
Fixarse na liña 8, que enviamos ao construtor da clase ArrayAdapter o layout que vai 'gardar' cada elemento da lista no spinner.


  • Agora, para que funcione o adaptador temos que sobreescribir a lo menos tres métodos:
  • int getCount(): Devolve o número de elementos da lista. Fixarse que no noso caso, o número de elementos da lista o sabemos por calquera dos dous arrays onde gardamos os datos. Se creamos catro elementos, a propiedade textos.length será catro.
  • View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent): Este método ten que devolver o view de cada elemento da fila. Fixarse que este 'view' no noso caso será un LinearLayout formado por dos Views (un TextView e un ImageView). E o view que visualiza o elemento escollida da lista.
  • View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent): Devolve o view que conforma cada elemento da lista cando prememos sobre a mesma (a lista despregable). Pero aquí amosamos o view de cada elemento da lista despregable.
Fixarse que no caso dos métodos que devolven un view, podemos facer nos un dinamicamente e devolvelo.
Por exemplo, se fago isto:
  1.     @Override
  2.     public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
  3.         TextView proba = new TextView(mContext);
  4.         proba.setText("OOOOOOOO");
  5.         return proba;
  6.     }
Aparece isto:
PDM adaptador 11.jpg
Isto sería útil se queremos que cando escollamos un elemento apareza unha información e cando estea escollido apareza outra. Máis información neste enlace.


No noso caso queremos que visualmente apareza o mesmo cando temos un elemento escollido da lista, como cando aparece o despregable da mesma.
Como o view que representa o elemento seleccionado da lista o obtemos do método getView (como comentamos antes) o código quedaría así:
  1.     @Override
  2.     public int getCount() {
  3.         return textos.length;       // Poderíamos poñer tamén o número de imaxes.
  4.     }
  5.  
  6.     @Override
  7.     public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
  8.         return getView(position,convertView,parent);
  9.     }
  10.  
  11.     @NonNull
  12.     @Override
  13.     public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
  14.         return super.getView(position, convertView, parent);
  15.     }
  • Liña 3: Devolvemos o número de textos enviados como parámetro do constructor.
  • Liña 8: Devolvemos o view do método getView que imos a modificar.



  • Agora ven o máis importante, que é crear o view que conforma o elemento seleccionado no Spinner:
PDM adaptador 12.jpg
O proceso para facelo é o seguinte:
Fixámonos na definición do método getView: public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Ese obxecto da clase View vai 'levar' o layout que temos definido para cada elemento da fila.
E os datos cos que vai encher dito layout van ir no método setTag xa comentado nesta wiki.
  • O primeiro é cargar o layout no 'convertView'.
Para iso temos que pasar o layout dun arquivo XML a un obxecto que poida ser empregado en programación.
Iso se fai facendo un 'inflate':
  1.             LayoutInflater mInflater = (LayoutInflater) mContext.
  2.                     getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  3.             convertView = mInflater.inflate(R.layout.spinner_ud04_04, parent, false);
Xa analicaremos en detalle este código. Por agora quedade coa idea de que estas liñas fan que o LinearLayout co botón e a imaxe pasa a ser un obxecto que se garda en convertView.
  • Segundo, debemos de pasar os datos de cada elemento por medio do método setTag.
Non perdades a idea de que a este método se chama 'por cada elemento da lista', sendo o parámetro 'position' o que nos di a posición do elemento que se vai amosar.
Para facer isto, crearemos una clase na que gardaremos os views que se van pasar ao layout. Os views son un ImageView e un TextView:
  1.     private static class ViewHolder {
  2.         ImageView mImaxe;
  3.         TextView mTexto;
  4.     }
Agora creamos un obxecto de dita clase e indicamos a que se corresponde cada un dese views no arquivo de Layout. Ademáis gardamos dita información no convertView, na propiedade Tag:
  1.             Adaptador_UD04_04_Spinners.ViewHolder viewFila = new Adaptador_UD04_04_Spinners.ViewHolder();
  2.  
  3.             viewFila.mImaxe = (ImageView) convertView.findViewById(R.id.imgVImaxen_UD04_04_Spinners);
  4.             viewFila.mTexto = (TextView) convertView.findViewById(R.id.txtTexto_UD04_04_Spinners);
  5.             convertView.setTag(viewFila);
  • Terceiro, asociamos os datos concretos de cada elemento aos datos de cada view e devolvemos o 'convertView':
  1.         viewFila.mImaxe.setImageResource(imaxes[position]);
  2.         viewFila.mTexto.setText(textos[position]);
  3.  
  4.         return convertView;


  • Cuarto, como a este método se pode chamar varias veces (é dicir, despregar a lista), a segunda ou sucesivas veces que se chame, os datos xa non cambian, polo que non é necesario volver a crear o 'converView' que xa virá con datos, incluído o tag, polo que podemos recuperar ditos datos có método getTag.
Agora se entende por que é necesario chamar ao método setNotifyOnChange(boolean notifyOnChange) ?
O código completo:

Arquivo: Adaptador_UD04_04_Spinners

  1. public class Adaptador_UD04_04_Spinners extends ArrayAdapter {
  2.  
  3.     int[] imaxes;   // Lista de imaxes a cargar. Lembra que en res todo son números  Se foran url poderíamos cambialo por String[]
  4.     String[] textos;
  5.     Context mContext;
  6.  
  7.     public Adaptador_UD04_04_Spinners(@NonNull Context context, int[]imaxes,String[]textos) {
  8.         super(context, R.layout.spinner_ud04_04);       // Enviamos o layout que imos utilizar
  9.  
  10.         this.imaxes = imaxes;
  11.         this.textos = textos;
  12.         this.mContext = context;
  13.     }
  14.  
  15.     @Override
  16.     public int getCount() {
  17.         //return super.getCount();
  18.         return textos.length;       // Poderíamos poñer tamén o número de imaxes.
  19.     }
  20.  
  21.     @Override
  22.     public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
  23.         return getView(position,convertView,parent);
  24.     }
  25.  
  26.     private static class ViewHolder {
  27.         ImageView mImaxe;
  28.         TextView mTexto;
  29.     }
  30.     @NonNull
  31.     @Override
  32.     public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
  33.         //return super.getView(position, convertView, parent);
  34.  
  35.         Adaptador_UD04_04_Spinners.ViewHolder viewFila = new Adaptador_UD04_04_Spinners.ViewHolder();
  36.         if (convertView == null) {
  37.             LayoutInflater mInflater = (LayoutInflater) mContext.
  38.                     getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  39.             convertView = mInflater.inflate(R.layout.spinner_ud04_04, parent, false);
  40.             viewFila.mImaxe = (ImageView) convertView.findViewById(R.id.imgVImaxen_UD04_04_Spinners);
  41.             viewFila.mTexto = (TextView) convertView.findViewById(R.id.txtTexto_UD04_04_Spinners);
  42.             convertView.setTag(viewFila);
  43.         } else {
  44.             viewFila = (Adaptador_UD04_04_Spinners.ViewHolder) convertView.getTag();
  45.         }
  46.         viewFila.mImaxe.setImageResource(imaxes[position]);
  47.         viewFila.mTexto.setText(textos[position]);
  48.  
  49.         return convertView;
  50.     }
  51.  
  52. }



  • Unha vez que temos o adaptador creado teremos que ir á activity e asociar o spinner a dito adaptador.
Como non temos moitas imaxes en /res/ imos asociar a mesma imaxe a todos os elementos da lista. Partimos que temos unha imaxe en res de nome: R.drawable.ok (se non é o caso poñede outra calquera).

Arquivo: UD04_04_Spinners

  1. package es.cursoandroid.cifprodolfoucha.aprendiendo.Adaptadores;
  2.  
  3. import android.app.Activity;
  4. import android.os.Bundle;
  5. import android.widget.Spinner;
  6.  
  7. import es.cursoandroid.cifprodolfoucha.aprendiendo.R;
  8.  
  9. public class UD04_04_Spinners extends Activity {
  10.  
  11.     private void cargarLista(){
  12.         String datos[] = getResources().getStringArray(R.array.planetas_UD02_01_spinner);
  13.         int[] imaxes = new int[datos.length];
  14.        for(int cont=0;cont<datos.length;cont++){
  15.            imaxes[cont]=R.drawable.ok;
  16.        }
  17.  
  18.         Spinner lista = findViewById(R.id.spnLista_UD04_04_Spinners);
  19.  
  20.         Adaptador_UD04_04_Spinners meuAdaptador = new Adaptador_UD04_04_Spinners(this,imaxes,datos);
  21.         lista.setAdapter(meuAdaptador);
  22.  
  23.     }
  24.  
  25.     @Override
  26.     protected void onCreate(Bundle savedInstanceState) {
  27.         super.onCreate(savedInstanceState);
  28.         setContentView(R.layout.activity_ud04_04__spinners);
  29.  
  30.         cargarLista();
  31.     }
  32. }





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