viernes, 9 de septiembre de 2011

Elementos básicos del interface de usuario – Spinner (I) - Basic elements of the user interface

Un Spinner es un elemento que nos permite seleccionar un dato dentro de una lista de manera similar a como lo hacen los ‘ComboBox’ de otros lenguajes. Si la selección es de pocas opciones ya hemos visto que podemos utilizar un RadioGroup, pero cuando la lista se amplía, es conveniente utilizar un Spinner ya que si excede del tamaño de la pantalla nos permite hacer scroll automaticamente.

La definición en XML de un Spinner sería algo semejante a esto:

<Spinner
      android:id="@+id/spinner"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:entries="@array/arrayPaises"
      android:prompt="@string/spPais"
    >
</Spinner>

El atributo android:prompt="@string/spPais" indica el texto a mostrar cuando se muestra la lista de opciones.
El atributo android:entries="@array/arrayPaises" indica el nombre de un recurso desde el que obtener los datos para rellenar la lista. El array XML que contiene los elementos a mostrar en la lista podemos definirlo dentro del fichero /res/values/strings.xml aunque yo prefiero hacerlo en un fichero distinto llamado /res/values/arrays.xml por cuestiones de claridad. Este fichero tendría un formato semejante a este:
<?xml version="1.0" encoding="utf-8"?>
<resources>
   <string-array name="arrayPaises">
       <item>Ninguno</item>
       <item>Alemania</item>
       <item>Argentina</item>
       <item>Brasil</item>
       <item>España</item>
       <item>Francia</item>
       <item>Italia</item>
       <item>Mexico</item>
       <item>Peru</item>
      
       …
   </string-array>
</resources>

Si ejecutamos el proyecto directamente obtendremos una lista desplegable con scroll vertical incluido y un RadioButton en cada una de las opciones:

 
Spinner antes de pulsar para desplegarlo.

 
Spinner desplegando las opciones.

Esta es la manera más simple de cargar un Spinner utilizando unicamente su definición en /res/layout/main.xml y un fichero de recursos en /res/values/arrays.xml.

Cargando un recurso XML en un Spinner desde Java
Ahora bien, si queremos tener el control del contenido del Spinner e incluso modificar el aspecto con el que se muestra, deberemos empezar a tocar código java. Android nos proporciona una herramienta poderosa para cargar listas llamada ‘ArrayAdapter’. Para implementarlo deberemos eliminar el atributo android:entries="@array/arrayPaises" del fichero /res/values/main.xml e incluir el siguiente código java:


public class PruebaSpinner2Activity extends Activity {
     
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        Spinner spPaises = (Spinner) findViewById (R.id.spinner);
        ArrayAdapter<CharSequence> aa_paises =
              ArrayAdapter.createFromResource
             (this, R.array.arrayPaises, android.R.layout.simple_spinner_item);
        spPaises.setAdapter(aa_paises); 
    }
}

El método ArrayAdapter.createFromResource nos permite cargar un fichero de recursos XML automaticamente y recibe tres parámetros:
  • El contexto en que debe aparecer (normalmente el actual al que haremos referencia con ‘this’)
  • El nombre del fichero de recursos XML.
  • La manera en que será mostrada la lista. Android proporciona una serie de Layouts predefinidos de los cuales los mas habituales son:
    • simple_spinner_item: Muestra una lista simple (Ver imagen más abajo)
    • simple_spinner_dropdown_item: Muestra una lista con un RadioButton en cada opción (Como hemos visto antes).
Por último, lo único que tenemos que hacer es asignar el ArrayAdapter al Spinner con la instrucción: spPaises.setAdapter(aa_paises);  

 
Vista del Spinner con el Layout simple_spinner_item

Cargando un Array de Strings en un Spinner desde Java
Si lo que queremos es rellenar el Spinner con datos almacenados en un Array de datos String (que hemos podido cargar de una base de datos) debemos utilizar el ArrayAdapter con otro formato:


public class PruebaSpinner2Activity extends Activity {
     
      String[] paises = { "Ninguno", "Alemania", "Argentina",
                  "Brasil", "España", "Francia",
                  "Italia", "Mexico", "Peru"};
     
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        Spinner spPaises = (Spinner) findViewById (R.id.spinner);
        ArrayAdapter<String> aa_paises = new ArrayAdapter<String>(
                  this, android.R.layout.simple_spinner_item, paises);
        spPaises.setAdapter(aa_paises); 
    }
}


En este caso los tres parámetros del ArrayAdapter cambian de sitio de forma que el último corresponde al nombre del Array de Strings.


Cargando manualmente un Spinner desde Java
Podemos tomar el control absoluto del contenido del Spinner cargando manualmente nuestro ArrayAdapter. Por ejemplo:

public class PruebaSpinner2Activity extends Activity {
     
      String[] paises = { "Ninguno", "Alemania", "Argentina",
                  "Brasil", "España", "Francia",
                  "Italia", "Mexico", "Peru"};
     
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        Spinner spPaises = (Spinner) findViewById (R.id.spinner);
        ArrayAdapter<String> aa_paises = new ArrayAdapter<String> (this, android.R.layout.simple_spinner_item);
       
        aa_paises.add("Ninguno");
        for (int x=0; x<paises.length; x++) {
            if (paises[x].charAt(0) > 'A' && paises[x].charAt(0) < 'M') {
                  aa_paises.add(paises[x]);
            }
        }
               aa_paises.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
       spPaises.setAdapter(aa_paises); 
    }
}

He definido un ArrayAdapter básico sin incluir ninguna fuente de datos. Después he cargado manualmente con el método ‘adaptador.add(Object)’ los elementos del array de paises que comienzen por una letra mayor de ‘A’ y menor de ‘M’ y, por último he asociado al adaptador el formato simple_spinner_dropdown_item con el método ‘adaptador.setDropDownViewResource’. Asociamos el ArrayAdapter al Spinner y obtenemos el resultado:
 
Además de add, hay otros métodos interesantes para el ArrayAdapter que nos permiten manejarlo completamente como por ejemplo:
  • clear. Limpia el ArrayAdapter de su contenido.
  • insert. Incluye un nuevo elemento a partir de una posición determinada.
  • getItem. Obtiene el contenido de un determinado elemento.
  • remove. Elimina un determinado elemento.

En la próxima entrada veremos cómo controlar el elemento que se ha seleccionado en el Spinner.

Hasta pronto.

3 comentarios:

  1. No hay alguna forma de llenar el spinner con objetos de una clase y no solo strings?

    ResponderEliminar
    Respuestas
    1. Muchas gracias por compartir tu conocimiento con todos nosotros, tengo la siguiente duda:

      Estoy manejando una base de datos SQlite la cual traigo la información por medio de RecyclerView Id, nombre, descripción, y cuento con un Spinner el cual tiene unos valores predeterminados.

      Y quiero que cuando ingrese a la actividad y seleccione un valor del spinner este sea guardado en la base de datos SQlite y después cuando uno vuelva a ingresar a la actividad se vea es el valor seleccionado.

      Agradezco toda la ayuda que me pueda prestar.

      Tengo las siguientes clases JAVA, si tienes un correo te las adjuntaré ya que aqui no me las dejo pegar.

      1. Activity donde llamo toda la información.
      2. Helper donde realizo el proceso insertar, actualizar la base de datos.
      3. Creación de la base de datos.
      4. El adaptador del Recyclerview

      Quedo atento a toda la colaboración que me puedas dar.

      Eliminar
  2. Muchas gracias por compartir tu conocimiento con todos nosotros, tengo la siguiente duda:

    Estoy manejando una base de datos SQlite la cual traigo la información por medio de RecyclerView Id, nombre, descripción, y cuento con un Spinner el cual tiene unos valores predeterminados.

    Y quiero que cuando ingrese a la actividad y seleccione un valor del spinner este sea guardado en la base de datos SQlite y después cuando uno vuelva a ingresar a la actividad se vea es el valor seleccionado.

    Agradezco toda la ayuda que me pueda prestar.

    Tengo las siguientes clases JAVA, si tienes un correo te las adjuntaré ya que aqui no me las dejo pegar.

    1. Activity donde llamo toda la información.
    2. Helper donde realizo el proceso insertar, actualizar la base de datos.
    3. Creación de la base de datos.
    4. El adaptador del Recyclerview

    Quedo atento a toda la colaboración que me puedas dar.

    ResponderEliminar