Programación Android, cómo usar un Spinner I

Share if you like...Share on Facebook0Tweet about this on TwitterShare on Google+0Share on LinkedIn0

Después de un par de semanas de inactividad, debido a que ha habido que finalizar 2 proyectos y apenas ha quedado tiempo libre, volvemos a la publicar una nueva entrada.

En esta ocasión vamos a intentar explicar el uso y comportamiento de un Spinner.

Un Spinner es un elemento que ofrece un desplegable en el que poder seleccionar una de múltiples opciones, en el que además se visualiza la opción seleccionada de entre las disponibles:

Spinner desplegado
Spinner desplegado

Para explicar su funcionamiento, cómo rellenarlo de datos y las opciones más utilizadas vamos a utilizar un ejemplo en el que rellenaremos el Spinner con animales, y al seleccionar uno mostraremos una pequeña descripción del animal.

Creando el Spinner

En primer lugar necesitaremos crear un Layout que contenga un Spinner y un EditText multilinea en el que se mostrará la descripción de la opción elegida en el Spinner. Esta podría ser una opcion:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".SpinnerMain" >

    <Spinner
        android:id="@+id/spAnimals"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:entries="@array/animals" />

    <EditText
        android:id="@+id/etDescription"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/spAnimals"
        android:ems="10"
        android:focusable="false"
        android:inputType="textMultiLine" />

</RelativeLayout>

Introduciendo datos en el Spinner desde XML

Una vez que hemos creado el layout, necesitaremos rellenar el layout con los animales que queramos, para eso tenemos dos opciones distintas:

  • Crear un recurso string-array en XML en el que indiquemos todos los nombres de los animales:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="animals">
        <item>Perro</item>
        <item>Gato</item>
        <item>Caballo</item>
        <item>Canario</item>
        <item>Vaca</item>
        <item>Cerdo</item>
    </string-array>
</resources>
  • Crear la colección de nombres en código Java, ejemplo:
private final static String[] names = { "Perro", "Gato", "Caballo",
			"Canario", "Vaca", "Cerdo" };

La ventaja que ofrece la primera forma es que al tener el recurso previamente configurado, se puede asignar directamente en el XML del layout al propio Spinner, sin necesidad de código extra en Java. Para ello utilizaríamos el atributo android:entries=”” y le daremos como valor el nombre que asignamos al string-array que contiene los nombres de los animales. En el caso de nuestro ejemplo sería android:entries=”@array/animals”. Sin embargo para utilizar la colección desde el código Java tendremos que crear un Adapter (una clase que sirve de puente entre el Spinner y la colección de datos que contiene, y que se encarga de crear las vistas necesarias para mostrar los datos). Este tipo de objeto lo explicaremos más adelante, cuando mostremos cómo mostrar vistas personalizadas para estos datos (por ejemplo al lado del nombre del animal se podría poner una imagen).

Cada opción tiene una utilidad distinta: Si son opciones fijas utilizaremos un recurso XML que nos ahorrará trabajo. Si son opciones dinámicas (datos introducidos en una Base de Datos por ejemplo), la tendremos que gestionar obligatoriamente a través del código Java. Por esto voy a tratar de explicar las dos formas de utilizar el Spinner.

Introduciendo datos en el Spinner desde Java

La primera forma de rellenar el Spinner (a partir del XML) ya la hemos explicado, falta explicar cómo hacerlo desde el código Java. Para rellenar el Spinner en primer lugar crearemos el adapter que hemos mencionado, utilizaremos el ArrayAdapter para esto. Esta clase tiene varios constructores, que se podrán ver en Android Developer. En este ejemplo utilizaremos el constructor que utiliza un Context (el propio de la Activity), un recurso para mostar datos (la vista, utilizamos una por defecto de Android) y el array de String que hemos creado:

ArrayAdapter adapter = new ArrayAdapter<String>(this,
	android.R.layout.simple_spinner_dropdown_item, names);

Ahora tenemos que asignar el adapter que hemos creado al Spinner que tenemos, para eso declararemos una variable de Spinner, que inicializaremos apuntando al Spinner que hemos creado en el layout, posteriormente le asignaremos el adapter al Spinner:

spAnimals = (Spinner)findViewById(R.id.spAnimals);
spAnimals.setAdapter(adapter);

Con esto ya hemos creado nuestro Spinner, y hemos rellenado los datos para que se muestren al desplegarlo, en la siguiente entrada crearemos las descripciones de los diferentes animales y haremos que el EditText las muestre en función de la opción elegida en el Spinner.

En la siguiente entrada mostraremos una descripción en función de la opción del Spinner elegida.

Descargas

Puedes ver el resultado del ejemplo en tu móvil descargando nuestra aplicación desde Google Play.

Share if you like...Share on Facebook0Tweet about this on TwitterShare on Google+0Share on LinkedIn0
The following two tabs change content below.
Reborn as IT Developer. Desarrollador Android y fundador de Proyecto Simio. "En realidad, yo no puedo enseñar nada a nadie, sólo puedo hacerles pensar." - Sócrates.

22 thoughts on “Programación Android, cómo usar un Spinner I

  1. Buenas tardes amigo quisiera que me puedas ayudar, creé un login así de común con ID y su respectivo password, pero ahora quisiera adicionarle un spinner el cual sea un parámetro adicional para el logeo, y que estos datos del spinner también estén en una base de datos MySql; es decir, el usuario XXXX con ID juan contraseña juan y que su atributo del spinner sea juan y este dato salga en la lista del spinner. Es posible? ayúdame please :(

  2. Tengo una duda, si yo deseo agregar el Spinner dentro de un fragment, en el momento en que utilizo el THIS me genera un problema.

    ArrayAdapter adaptador = new ArrayAdapter (this, android.R.layout.simple_spinner_item, datos);
    lista.setAdapter(adaptador);

    Intente con getContext() pero me dice que no funciona en un API inferior a 23 quisiera saber si saben como puedo solucionar esto.

    Gracias

    1. Fíjate en qué tipo de parámetro pide donde pasas el this, es un context, que el fragment no tiene.

      Prueba a pasar “getActivity()” para usar el contexto de la activity que gestiona el fragment.

  3. Buenas , no entiendo muy bien como llenar un spinner, yo hago un llamado a un webservice, que me trae muchos ID y sus descripciones, en el spinner quiero mostrar solo la descripción y al seleccionar una descripción quiero que se rescate el valor del ID asociado a la descripción. Quién podría ser tan amable de explicarme con manzanas como realizar esta acción, se lo agradecería demasiado, saludos.

    1. Tengo esta clase:

      public class StringWithTag {
      public String idinterno;
      public String descinterna;

      public StringWithTag(String id, String desc) {
      idinterno = id;
      descinterna = desc;
      }

      public String GetId() {
      return idinterno;
      }
      }

      Luego creo una lista de tipo StringWihtTag y le paso los valores de mi web services (id y descripción). Una vez que llene la lista la retorno y la rescato en mi activity para pasarla a un adapter, el adapter como debería rescatar esos datos?.

      1. Buscando en google puedes encontrar tutoriales sobre cómo crear spinners personalizados como este:
        http://mrbool.com/how-to-customize-spinner-in-android/28286

        Sobre estos ejemplos sólo tendrías que tener en cuenta que tú sólo quieres mostrar un texto, por lo que en el xml para el item sólo tendrías que añadir un TextView, y en él escribirías lo que quieras mostrar (la descripción).

        Para luego recoger lo que se selecciona del spinner tienes dos formas, una a través del Listener OnItemSelectedListener, que tiene dos métodos. Uno de ellos tiene la siguiente firma: public void onItemSelected(AdapterView< ?> adapter, View view, int position, long id). Como ves, ese método te devuelve la posición del objeto seleccionado, sólo tendrías que pedirle al adapter el objeto que tiene en esa posición y obtendrías tu objeto con id y desc. La segunda forma sería si por ejemplo tuvieras que esperar a que el usuario pulsara un botón para recoger los valores, en ese caso el código sería así:
        int pos = spiner.getSelectedItemPosition();
        StringWithTag swt = adapter.getItem(pos);
        String id = swt.getId();

        Un saludo.

  4. Consulta: Quiero llenar mi spinner con datos que me devuelve un arreglo bidimensional
    ej: Arreglo[0][0] = gato
    Arreglo[0][1]= 10
    Arreglo[1][0]= perro
    Arreglo[1][1]= 12

    Quiero llenar mi spinner con esos elementos.Quiero que muestre la descripción (perro , gato) en el despliegue y que por debajo al seleccionarlo se pueda recuperar el ID que está asociado a cada uno de esos elementos.

    ¿Se puede?

    1. Por poder se puede, pero es complicar demasiado la lógica…

      Puedes pasar el arreglo al adapter del spinner (un adapter personalizado obligatoriamente), y crear un método getItemID(int position), donde position será el primer índice y preguntarás por “1” en el segundo índice, de manera que si se selecciona “gato” pasará su index = 0, y el método getItemID hará un “return [index][1]”, que al haber pasado “0” devolverá 10.

      En cualquier caso no te recomiendo hacer algo así, es mejor usar una clase modelo que contenga la variable ID además de lo que quieras mostrar en el spinner, de manera que cuando tengas que preguntar al adapter le pides el item de la posición seleccionada, y a ese item sólo le tendrás que preguntar su ID.

      Muchas gracias por el comentario, un saludo :)

  5. para llenarlo con un json? no llogro hacerlo encuentro ejemplos de como llenarlo con otras 3 fuentes pero no con un json que me devuelve un web service

  6. Hola

    Estoy usando el objeto Spinner, agrego un promt al XML que será el titulo de dicho Spiner “Seleccione una opción”, este titulo le quiero cambiar tanto el color de la letra así como el backgroud , cómo puedo hacer esto? … Gracias & Saludos.

    1. En estos casos lo que yo suelo hacer es usar un adapter personalizado, y al crear la lista añado al listado de objetos uno “extra” que va en el primer lugar de la colección en el que pongo lo del “seleccione una opción”. Al usar este adapter personalizado, en los métodos que montan la vista, puedo definir colores sin problemas para el elemento que ocupe la posición 0.

      Un saludo.

  7. Buenas de nuevo,

    Sigo pegándome con el diseño del layout. La cosa es que necesito “pintar” una serie de spinner, que no siempre tiene porque ser la misma, es decir, hago un bucle for en el que recorro un json y tendré tantos spinner como campos tengan la propiedad “Seleccion”. No se si me estoy explicando bien. La cosa es que soy capaz a sacarlos todos….pero unos encima de otros :( algo se me está escapando y no doy con el quiz. ¿Se puede hacer así o no es posible?
    Muchisimas gracias de antemano!!

    1. Puedes hacer lo que quieres sin problema, pero tendrás que jugar con LayoutParams para indicar que se vayan colocando un spinner debajo del anterior. Intuyo que al hacerlo con un bucle for estás perdiendo la referencia al anterior spinner creado, y eso está haciendo que ya no puedas decir al siguiente spinner que se posicione debajo del primero. De ser así tendrías que replantear ese código para tener un objeto de cada posible spinner que necesites, y así poder ordenarlos en condiciones. Sólo los mostrarás cuando te sea necesario, pero el objeto lo tendrás en el código para poder organizar la posición de tus controles en el layout sin problemas.

      También estudia la posibilidad de crear el layout en xml, y mostrar u ocultar los elementos que necesites en cada momento, y sólo tendrías que decir en código que el spinner que estuviera debajo del que ocultas se sitúe debajo del anterior que no hayas ocultado, así te podrías evitar problemas.

  8. Buenas,
    Me gustaría saber si es posible crear el Spinner desde código, es decir, sin definirlo previamente en el xml, puesto que mi intención es que se cree el spinner si una determinada condición se cumple.
    Lo intento con:
    Spinner spinner1 = new Spinner(this);
    y creo el adapter y se lo aplico, pero no consigo ver nada, el spinner no aparece :(
    Muchas gracias de antemano,

    Elena

    1. Buenas Elena.

      Efectivamente, sí se puede crear desde código, y lo que estás haciendo está bien, pero es la mitad del trabajo. Ten en cuenta que en Android trabajamos con una Activity en 2 capas distintas, una es la vista, lo que se ve en pantalla, que corresponde al Layout, y otra es el controlador de esa vista, que es el código Java que escribimos.

      Si necesitas crear y mostrar un Spinner en pantalla, primero debes crearlo como dices, pero te falta asignárselo después al Layout. Para eso tendrías que definir una serie de LayoutParams, que son los ajustes que haríamos en el xml como el ancho, alto, a la derecha de XXX control, margen, etc., y una vez definidos estos parámetros se lo asignarías al Layout, para que finalmente se mostrara.

      También puedes asignarlo sin definir los LayoutParams, pero en ese caso no podrías controlar en qué lugar de la pantalla se muestra el control que añades.

      Un ejemplo sobre cómo asignar los LayoutParams sería:

      RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
      params.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
      Button button1;
      button1.setLayoutParams(params);
      
      params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
      params.addRule(RelativeLayout.RIGHT_OF, button1.getId());
      Button button2;
      button2.setLayoutParams(params);

      Para posteriormente añadir el control al Layout y que se muestre en pantalla sería, si tienes ya un control de la vista referenciado en el código:

      RelativeLayout rl = (RelativeLayout) control.getParent();
      rl.add(nuevoControl); 

      Si no tienes ningún control ya referenciado en Java tendrías que darle un id al layout en XML y lo harías así:

      RelativeLayout rl = (RelativeLayout) findViewByID(R.id.idLayout);
      rl.add(nuevoControl)

      Con esto ya tendrías que ver tu nuevo control en pantalla :)

        1. Uy que va! me ha venido estupendamente tu comentario!! ahora estaba intentando controlar el ancho,alto etc…. Muchisimas gracias!! :) me aparecia el spinner si…pero ocupando el layout enterito!! perfecta la información! otra vez mil gracias!

Deja un comentario