Interfaz de usuario en Android: Controles de selección (I)

Una vez repasados los controles básicos (I, II, III) que podemos utilizar en nuestras aplicaciones Android, vamos a dedicar los próximos artículos a describir los diferentes controles de selección disponibles en la plataforma. Al igual que en otros frameworks Android dispone de diversos controles que nos permiten seleccionar una opción dentro de una lista de posibilidades. Así, podremos utilizar listas desplegables (Spinner), listas fijas (ListView), tablas (GridView) y otros controles específicos de la plataforma como por ejemplo las galerías de imágenes (Gallery).

En este primer artículo dedicado a los controles de selección vamos a describir un elemento importante y común a todos ellos, los adaptadores, y lo vamos a aplicar al primer control de los indicados, las listas desplegables.

Adaptadores en Android (adapters)

Para los desarrolladores de java que hayan utilizado frameworks de interfaz gráfica como Swing, el concepto de adaptador les resultará familiar. Un adaptador representa algo así como una interfaz común al modelo de datos que existe por detrás de todos los controles de selección que hemos comentado. Dicho de otra forma, todos los controles de selección accederán a los datos que contienen a través de un adaptador.

Además de proveer de datos a los controles visuales, el adaptador también será responsable de generar a partir de estos datos las vistas específicas que se mostrarán dentro del control de selección. Por ejemplo, si cada elemento de una lista estuviera formado a su vez por una imagen y varias etiquetas, el responsable de generar y establecer el contenido de todos estos “sub-elementos” a partir de los datos será el propio adaptador.

Android proporciona de serie varios tipos de adaptadores sencillos, aunque podemos extender su funcionalidad facilmente para adaptarlos a nuestras necesidades. Los más comunes son los siguientes:

  • ArrayAdapter. Es el más sencillo de todos los adaptadores, y provee de datos a un control de selección a partir de un array de objetos de cualquier tipo.
  • SimpleAdapter. Se utiliza para mapear datos sobre los diferentes controles definidos en un fichero XML de layout.
  • SimpleCursorAdapter. Se utiliza para mapear las columnas de un cursor abierto sobre una base de datos sobre los diferentes elementos visuales contenidos en el control de selección.

Para no complicar excesivamente los tutoriales, por ahora nos vamos a conformar con describir la forma de utilizar un ArrayAdapter con los diferentes controles de selección disponibles. Más adelante aprenderemos a utilizar el resto de adaptadores en contextos más específicos.

Veamos cómo crear un adaptador de tipo ArrayAdapter para trabajar con un array genérico de java:

final String[] datos =
        new String[]{"Elem1","Elem2","Elem3","Elem4","Elem5"};

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

Comentemos un poco el código. Sobre la primera línea no hay nada que decir, es tan sólo la definición del array java que contendrá los datos a mostrar en el control, en este caso un array sencillo con cinco cadenas de caracteres. En la segunda línea creamos el adaptador en sí, al que pasamos 3 parámetros:

  1. El contexto, que normalmente será simplemente una referencia a la actividad donde se crea el adaptador.
  2. El ID del layout sobre el que se mostrarán los datos del control. En este caso le pasamos el ID de un layout predefinido en Android (android.R.layout.simple_spinner_item), formado únicamente por un control TextView, pero podríamos pasarle el ID de cualquier layout personalizado de nuestro proyecto con cualquier estructura y conjunto de controles, más adelante veremos cómo (en el apartado dedicado a las listas fijas).
  3. El array que contiene los datos a mostrar.

Con esto ya tendríamos creado nuestro adaptador para los datos a mostrar y ya tan sólo nos quedaría asignar este adaptador a nuestro control de selección para que éste mostrase los datos en la aplicación.

Una alternativa a tener en cuenta si los datos a mostrar en el control son estáticos sería definir la lista de posibles valores como un recurso de tipo string-array. Para ello, primero crearíamos un nuevo fichero XML en la carpeta /res/values llamado por ejemplo valores_array.xml e incluiríamos en él los valores seleccionables de la siguiente forma:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="valores_array">
        <item>Elem1</item>
        <item>Elem2</item>
        <item>Elem3</item>
        <item>Elem4</item>
        <item>Elem5</item>
    </string-array>
</resources>

Tras esto, a la hora de crear el adaptador, utilizaríamos el método createFromResource() para hacer referencia a este array XML que acabamos de crear:

ArrayAdapter<CharSequence> adapter =
    ArrayAdapter.createFromResource(this,
        R.array.valores_array,
        android.R.layout.simple_spinner_item);

Control Spinner [API]

Las listas desplegables en Android se llaman Spinner. Funcionan de forma similar al de cualquier control de este tipo, el usuario selecciona la lista, se muestra una especie de lista emergente al usuario con todas las opciones disponibles y al seleccionarse una de ellas ésta queda fijada en el control. Para añadir una lista de este tipo a nuestra aplicación podemos utilizar el código siguiente:

<Spinner android:id="@+id/CmbOpciones"
	android:layout_width="match_parent"
	android:layout_height="wrap_content" />

Poco vamos a comentar de aquí ya que lo que nos interesan realmente son los datos a mostrar. En cualquier caso, las opciones para personalizar el aspecto visual del control (fondo, color y tamaño de fuente, …) son las mismas ya comentadas para los controles básicos.

Para enlazar nuestro adaptador (y por tanto nuestros datos) a este control utilizaremos el siguiente código java:

private Spinner cmbOpciones;

//...

cmbOpciones = (Spinner)findViewById(R.id.CmbOpciones);

adaptador.setDropDownViewResource(
        android.R.layout.simple_spinner_dropdown_item);

cmbOpciones.setAdapter(adaptador);

Comenzamos como siempre por obtener una referencia al control a través de su ID. Y en la última línea asignamos el adaptador al control mediante el método setAdapter(). ¿Y la segunda línea para qué es? Cuando indicamos en el apartado anterior cómo construir un adaptador vimos cómo uno de los parámetros que le pasábamos era el ID del layout que utilizaríamos para visualizar los elementos del control. Sin embargo, en el caso del control Spinner, este layout tan sólo se aplicará al elemento seleccionado en la lista, es decir, al que se muestra directamente sobre el propio control cuando no está desplegado. Sin embargo, antes indicamos que el funcionamiento normal del control Spinner incluye entre otras cosas mostrar una lista emergente con todas las opciones disponibles. Pues bien, para personalizar también el aspecto de cada elemento en dicha lista emergente tenemos el método setDropDownViewResource(ID_layout), al que podemos pasar otro ID de layout distinto al primero sobre el que se mostrarán los elementos de la lista emergente. En este caso hemos utilizado otro layout predefinido an Android para las listas desplegables (android.R.layout.simple_spinner_dropdown_item), formado por una etiqueta de texto con la descripción de la opción y un marcador circular a la derecha que indica si la opción está o no seleccionada (esto último sólo para Android 2.x)..

Con estas simples lineas de código conseguiremos mostrar un control como el que vemos en las siguientes imágenes, primero para Android 2.x y después para la versión 4.x:

Android Control Spinner (sin desplegar) Android Control Spinner (desplegado)

 

 

 

spinner-1-android4 spinner-2-android4

 

Como se puede observar en las imágenes, la representación del elemento seleccionado (primera imagen) y el de las opciones disponibles (segunda imagen) es distinto, incluyendo el segundo de ellos incluso algún elemento gráfico a la derecha para mostrar el estado de cada opción (en este caso, sólo para Android 2). Como hemos comentado, esto es debido a la utilización de dos layouts diferentes para uno y otros elementos.

En cuanto a los eventos lanzados por el control Spinner, el más comunmente utilizado será el generado al seleccionarse una opción de la lista desplegable, onItemSelected. Para capturar este evento se procederá de forma similar a lo ya visto para otros controles anteriormente, asignadole su controlador mediante el método setOnItemSelectedListener():

cmbOpciones.setOnItemSelectedListener(
    	new AdapterView.OnItemSelectedListener() {
		public void onItemSelected(AdapterView<?> parent,
			android.view.View v, int position, long id) {
   				lblMensaje.setText("Seleccionado: " + datos[position]);
		}

		public void onNothingSelected(AdapterView<?> parent) {
			lblMensaje.setText("");
		}
});

A diferencia de ocasiones anteriores, para este evento definimos dos métodos, el primero de ellos (onItemSelected) que será llamado cada vez que se selecciones una opción en la lista desplegable, y el segundo (onNothingSelected) que se llamará cuando no haya ninguna opción seleccionada (esto puede ocurrir por ejemplo si el adaptador no tiene datos).

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

En el siguiente artículo describiremos el uso de controles de tipo lista (ListView).

Curso de Programación Android en PDF

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

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

Más información:

, , , , , , ,

32 Responses to Interfaz de usuario en Android: Controles de selección (I)

  1. Jordi 23/12/2010 en 12:22 #

    Hola,

    Primero de todo agradecer el curro de hacer el tutorial, es genial!

    Sobre este tema en concreto de Spinner, cuando defines el Adapter

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

    Haces referencia a un layout.

    Además, defines un objeto spinner con id “CmbOpciones”. Y referencias la opcióin DropDrow al “simple_spinner_dropdown_item”.

    El “simple_spinner_item” no sería el “CmbOpciones”?

    Si accedes a ellos mediante R.layout, son LinearLayout o algun otro parecido?

    Muchas gracias!

    Jordi.

  2. sgoliver 23/12/2010 en 12:56 #

    Hola Jordi,

    CmbOpciones no es un layout xml, es la lista desplegable como tal, el objeto completo, por decirlo de alguna forma.

    Por su parte, simple_spinner_item es el layout xml que se va a usar para representar CADA elemento individual de la lista desplegable, es decir, cada linea de la lista por separado. Se puede utilizar cualquier layout que definas tú mismo en la carpeta \res\layout pero para no complicar el ejemplo he utilizado uno que ya viene predefinido en el SDK de Android (por eso comienza por “android.R.layout”, en vez de “R.layout”).

    Saludos.

  3. Juan Ospina 12/01/2011 en 10:47 #

    Muchas gracias!!! excelente informacion, me ha servido muchisimo

  4. Alexis 16/03/2011 en 4:49 #

    Hola amigo, antes que nada mil gracias por estos tutoriales, he tratado de aplicar este ejemplo pero me lanza error, el codigo completo del main.java es:

    package com.prueba.listview;

    import android.app.Activity;
    import android.os.Bundle;
    import android.widget.ArrayAdapter;
    import android.widget.Spinner;

    public class main extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    }

    final String[] datos =
    new String[]{“Elem1″,”Elem2″,”Elem3″,”Elem4″,”Elem5″};

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

    final Spinner cmbOpciones = (Spinner)findViewById(R.id.CmbOpciones);

    adaptador.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    cmbOpciones.setAdapter(adaptador);
    }

    Pero me salta erro en las ultimas dos lineas, el error es el siguiente:

    Multiple markers at this line
    - Syntax error on token “setDropDownViewResource”, Identifier expected after
    this token
    - Syntax error on token “.”, … expected
    - Syntax error on token “setDropDownViewResource”, Identifier expected after
    this token

    que podra ser?

    saludos

  5. Camilo Puentes 28/03/2011 en 4:22 #

    saludos Quiero Agradecerle por este aporte tan completo
    y quisiera preguntarle si ha intentado hacer un spinner con registros de una base de datos en sqlite sobre android y si lo ha intentado cual es la forma para hacerlo

    gracias
    Espero su respuesta

  6. Jlg 31/03/2011 en 12:14 #

    Buen curro y buen toutorial te has currado.

    Solo indicarte que tengo el mismo problema que Alexis,
    me dan los mismos errores en las 2 últimas líneas.
    He buscado y no veo por qué.

    Gracias.

  7. Jlg 31/03/2011 en 12:51 #

    Alexis, ya he visto el error.
    Es una cosa muy tona ;)

    Tienes que meter el código dentro de onCreate:

    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    //} <— Este es el problema

    final String[] datos =
    new String[]{“Elem1″,”Elem2″,”Elem3″,”Elem4″,”Elem5″};

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

    final Spinner cmbOpciones = (Spinner)findViewById(R.id.CmbOpciones);

    adaptador.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    cmbOpciones.setAdapter(adaptador);
    } // <– Aqui se cierra.
    }

  8. juanes 22/05/2011 en 22:46 #

    hola, me gustaria saber como poner en el Spinner, un texto que diga “seleccione una opcion”…con el prompt me sale este texto, pero cuando el spinner es desplegado…yo necesito que me muestre “seleccione una opcion”, pero sin desplegar el spinner..en su estado inicial por decirlo de alguna manera..gracias!!

  9. Agm 05/06/2011 en 16:40 #

    Hola, el codigo me da dos errores en las siguientes lineas:

    final Spinner cmbOpciones = (Spinner)findViewById(R.id.CmbOpciones); // El error aqui es:Cannot cast from View to Spinner

    cmbOpciones.setAdapter(adaptador); // El error aqui es: The method setAdapter(ArrayAdapter) is undefined for the type Spinner.

    Este es mi codigo:

    package net.sgoliver;

    import android.app.Activity;
    import android.os.Bundle;
    import android.widget.ArrayAdapter;

    public class Spinner extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    final String[] datos =
    new String[]{“Elem1″,”Elem2″,”Elem3″,”Elem4″,”Elem5″};

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

    final Spinner cmbOpciones = (Spinner)findViewById(R.id.CmbOpciones);

    adaptador.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    cmbOpciones.setAdapter(adaptador);
    }}

    Alguien sabra donde me estoy equivocando? gracias de antemano

  10. nise14 15/06/2011 en 22:01 #

    Saludes, excelentes tutoriales, tengo una duda, en un spinner no se puede poner un filtro, es que estoy llenando el spinner desde una base de datos que contiene mas de 1000 registros y es bastante incomodo desplazarse uno por uno, hasta encontrar el qeu necesito.

  11. Manuel 12/07/2011 en 21:20 #

    @Agm
    me ocurre exactamente los mismo que a ti. Le estoy dando vueltas y vueltas y no encuentro la solución.
    Lo has solucionado

  12. Manuel 12/07/2011 en 21:29 #

    @Agm y yo mismo,
    me auto respondo, el problema es que la clase se llama Spinner, y genera conflicto.
    Cambia el nombre. y funciona.

  13. enmanuel 23/10/2011 en 14:57 #

    Buenos dias

    exelente Tutorial gracias por dedicar tiempo,me gustaría que usted colocara una pagina explicando como colocar diferente imágenes en ListView.

    gracias

  14. Jajoo 28/10/2011 en 23:24 #

    HolA!

    Gracias como siempre :) Podrías dejar el enlace de la descarga del código como en el resto de los tutoriales? muchas gracias.

  15. poiel2010 05/01/2012 en 0:29 #

    El interes de andoid me ha despertado desde el año pasado, y me parece que para empezar esta muy bien, aunque soy estudiante de redes y telecomunicaciones. Muchas gracias por compartir sus conocimientos con tanta gente que estamos en esto, con deseos de mejorar personalmente y hacer un aporte a nuestra sociedad.

  16. Humberto 30/01/2012 en 22:42 #

    Muy Buen tutorial n__n Una duda: ¿Se puede Poner un ScrollBar (Barra de Desplazamiento) al Spinner? Esto para poder desplazarse y no aparesca todo el Menu de Opciones en la Pantalla, es bastante incomodo /: que aparescan todos xD es como ponerle un tope a los Items que hayamos puesto /:

  17. sgoliver 31/01/2012 en 12:03 #

    Hola Humberto,

    te animo a que expongas tu consulta en el foro de la web (http://www.sgoliver.net/foro) de forma que otros usuarios también puedan ayudarte. Saludos.

  18. Raymundo Castillo 11/02/2012 en 9:10 #

    buen día, antes que nada muchas gracias por estos excelentes cursos, tengo una duda, quisiera saber si en lugar de poblar el spinner con un array de String[] puedo hacerlo con un List ?. saludos!

  19. Luis Alejandro 14/01/2013 en 21:10 #

    Hola sgoliver, quisiera comentar que aproposito he ignorado el fragmento de codigo “adaptador.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);” y no noto ninguna diferencia, puesto o no puesto funciona de igual manera, quisiera saber porque y cual es la funcion de esta linea de codigo, gracias!

  20. David 24/02/2013 en 13:07 #

    En este blog, se están COPIANDO tus contenidos.
    Ejemplo: optimizarsinmas.blogspot.com.es/2011/03/mi-cuaderno-android-controles-de.html

  21. admin 25/02/2013 en 9:15 #

    Gracias por el aviso David.

  22. oso 27/04/2013 en 22:13 #

    Estimado muy bueno el tutorial pero tengo una consulta llevo varioa dias tratando de hacer que el spinner que yo tengo al momento de cargar me carge seleccionado un valor ejemplo tengo un appiner con los meses y quiero cuando aparesca el spinner salga seleccionado el mes actual seria de mucha ayuda si me puedes ayudar a solucionar el problema de antemano muchas gracias

  23. Omar A 20/05/2013 en 7:19 #

    Buenas, primero quisiera agradecerte y felicitarte por tan buenos tutoriales que hacen, espero que sigan asi, bueno quisiera preguntarles algo, espero que me entiendan lo que quiero…

    Bueno en este tutorial lo entendi todo, el problema es que al usar la alternativa 2, creando el arreglo en un xml yo le puse valores diferentes.

    Ya que aqui nada mas pone como darle valores a datos desde el MainActivity, de esto la siguiente linea de codigo

    final String[] datos = new String[]{“Elem1″,”Elem2″,”Elem3″,”Elem4″,”Elem5″};

    Me gustaria saber como darle los valores a datos desde el arreglo o el xml que se creo con lo valores para que esta linea de codigo

    lblMensaje.setText(“Seleccionado: ” + datos[position]);

    Me de los datos que estan en el xml, ya que si se deja asi me da los valores Elem1, Elem2.. etc, y no los que tengo en el valores_aray.xml

    De atenmano muchas gracias y espero que me hallan entendido lo que preguntaba :D

  24. js 16/09/2013 en 21:55 #

    tengo cargado un spinner con una simpleadapter.. cargos de un persona:
    id cargo
    15 administrador
    20 gerente
    22 contador..

    ArrayList<HashMap> registros = new ArrayList<HashMap>();

    cursor = myDataBase.rawQuery(sentencia, null);
    if (cursor.moveToFirst())
    do {
    HashMap Data = new HashMap();
    Data.put(“_id”, “” + cursor.getInt(0));
    Data.put(“cargo”, cursor.getString(1));
    registros.add(Data);
    } while (cursor.moveToNext());

    SimpleAdapter adapter = new SimpleAdapter(myContext, registros,
    android.R.layout.simple_spinner_item,
    new String[] { “cargo” }, new int[] { android.R.id.text1 });

    spinnerAreas.setAdapter(adapter);

    en mi proyecto consulto los datos de un de una persona de mi base de datos.. nombre, direccion… id_cargo…etc
    necesito q el spinner quede ubicado en el cargo que tiene la persona.
    quedaría muy agradecido su me pudieran colaborar con esto

  25. Palomita 26/11/2013 en 20:38 #

    Que tal un saludo a todos!!

    Bueno espero me puedan ayudar, desde ya gracias!!, mi problema es el siguiente: quiero sincronizar dos spinner, es decir, cuando se seleccione un item con indice X del spinner1 automaticamente el spinner2 cambie su indice al mismo del spinner1.

    Gracias!!

  26. Jose 12/12/2013 en 16:10 #

    Hola!

    estoy iniciandome en android y necesito hacer un spinner para mi aplicación. Me estoy basando en tu ejemplo pero tengo una duda.

    Cuando creas el adaptador para luego hacer referencia al archivo.xml que va en la carpeta menú:

    ArrayAdapter adapter = ArrayAdapter.createFromResource(this,
    R.array.valores_array, android.R.layout.simple_spinner_item);

    Cuando compilas salta un warning que dice que “adapter” nunca se usa. Me podeis ayudar a entender esto??. Gracias de ante mano.

  27. Jose 12/12/2013 en 16:13 #

    Perdón, me he equivocado de carpeta, quería decir values.

  28. Jose 12/12/2013 en 17:27 #

    Si estoy en lo cierto nunca se mostrara el contenido del archivo valores_array

  29. Arias 04/04/2014 en 23:14 #

    Que tal amigos, estoy siguiedo el curso muy interesante pero este tema lo veo con mas nivel de dificultad, que los anteriores temas y capitulos, bueno espero entenderlos todos y comprenderlos de la mejor manera…. saludos…. atte Arias

Trackbacks/Pingbacks

  1. Interfaz de usuario en Android: Controles de selección (II) | sgoliver.net blog - 07/09/2010

    [...] el artículo anterior ya comenzamos a hablar de los controles de selección en Android, empezando por explicar el [...]

  2. Interfaz de usuario en Android: Controles de selección (IV) | sgoliver.net blog - 11/09/2010

    [...] los dos controles de selección más comunes en cualquier interfaz gráfica, como son las listas desplegables (Spinner) y las listas “fijas” (ListView), tanto en su versión básica como optimizada, en este [...]

  3. Desarrollo en Android | sgoliver.net blog - 11/09/2010

    [...] Interfaz de usuario en Android: Controles de selección (I) [...]

Deja un comentario

Powered by WordPress. Designed by Woo Themes