Actualizado: Mayo 2020
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 por ejemplo listas desplegables (Spinner
), y listas fijas y tablas (RecyclerView
).
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)
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 fácilmente 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.
Veamos cómo crear un adaptador de tipo ArrayAdapter
para trabajar con un array genérico de kotlin:
val datos = arrayOf("Elem1", "Elem2", "Elem3", "Elem4", "Elem5") val adaptador = ArrayAdapter(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 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:
- El contexto, que normalmente será simplemente una referencia a la actividad donde se crea el adaptador.
- 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 controlTextView
, 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. - 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:
val adaptador = 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 a 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 kotlin:
cmbOpciones = findViewById(R.id.cmbOpciones) val adaptador = ArrayAdapter.createFromResource(this, R.array.valores_array, android.R.layout.simple_spinner_item) adaptador.setDropDownViewResource( android.R.layout.simple_spinner_dropdown_item) cmbOpciones.adapter = 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 penúltima 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 en 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.
Con estas simples lineas de código conseguiremos mostrar un control como el que vemos en la siguiente imagen:

En cuanto a los eventos lanzados por el control Spinner
, el más comúnmente 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, asignándole su controlador mediante la propiedad onItemSelectedListener
:
cmbOpciones.onItemSelectedListener = object: AdapterView.OnItemSelectedListener { override fun onNothingSelected(parent: AdapterView<*>) { lblSeleccion.text = "Sin selección" } override fun onItemSelected(parent: AdapterView<*>, view: View?, position: Int, id: Long) { val pos = parent.getItemAtPosition(position) lblSeleccion.text = "Seleccionado: $pos" } }
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). Además, vemos cómo para recuperar el dato seleccionado utilizamos el método getItemAtPosition()
del parámetro AdapterView
que recibimos en el evento. Para el ejemplo lo estoy mostrando sobre una etiqueta de texto, lblSeleccion
, que también he añadido a la interfaz.
CÓDIGO DEL ARTÍCULO: 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.
39 comentarios
[…] el artículo anterior ya comenzamos a hablar de los controles de selección en Android, empezando por explicar el […]
[…] 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 […]
[…] Interfaz de usuario en Android: Controles de selección (I) […]
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.
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.
Muchas gracias!!! excelente informacion, me ha servido muchisimo
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
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
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.
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.
}
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!!
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
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.
@Agm
me ocurre exactamente los mismo que a ti. Le estoy dando vueltas y vueltas y no encuentro la solución.
Lo has solucionado
@Agm y yo mismo,
me auto respondo, el problema es que la clase se llama Spinner, y genera conflicto.
Cambia el nombre. y funciona.
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
HolA!
Gracias como siempre :) Podrías dejar el enlace de la descarga del código como en el resto de los tutoriales? muchas gracias.
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.
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 /:
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.
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!
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!
En este blog, se están COPIANDO tus contenidos.
Ejemplo: optimizarsinmas.blogspot.com.es/2011/03/mi-cuaderno-android-controles-de.html
Gracias por el aviso David.
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
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
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
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!!
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.
Perdón, me he equivocado de carpeta, quería decir values.
Si estoy en lo cierto nunca se mostrara el contenido del archivo valores_array
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
Hola primero que nada tengo una duda , me podrian decir como puedo utilizar un spinner con multipantallas.
Lo que tiene que hacer el spinner es que al darle click a un elemento me lleve a otra pantalla ,es un trabajo para la escuela solo que tengo que hacerlo con un juego de cartas si me ayudan se los agradeceria bueno eso es todo gracias…..
[…] de los elementos de la lista desplegable y del control en sí, como ya explicamos en el artículo dedicado al control […]
gracias muy bueno siempre me han ayudado con mi tareas de android
Un excelente tutorial, gracias por compartir tus conocimientos con todos nosotros, tengo la siguiente duda: Tengo una base de datos ya creada y la cual se muestra en un Recyclerview con valores como Id, Nombre y Telefono y quiero colocar un spinner el cual me deje colocar una serie de valores, como puedo hacer para que cuando le de click en un valor del spinner se guarde dicho valor en SQLite y despues cuando vuelva a entrar a la actividad me muestre el valor guardado, agradezco toda la ayuda que me puedas brindar. Gracias.
Hola, muchas gracias por tu aporte, tengo la siguiente duda tengo un spinner el cual puedo seleccionar un valor, mi idea es que cuando lo seleccione quede guardado en una base de datos sqlite y que cuando vuelva ingresar a la actividad aparezca el valor que yo seleccione, tienes idea de cómo debo hacerlo, agradezco tu aporte.
Buenas tardes, en mi app tengo un spinner (desplegable) con una lista de item cargados en un String-array, el detalla es que al cargar mi lista de item varios sobrepasan el espacio (width) de mi spinner, por lo que las palabras se cortan y no se muestran, lo que busco de hacer es que mis item se coloquen en 2 lineas si sobre pasa ese limite.. Mi array es el siguiente
EXPENDIO DE ALIMENTOS O BIENES VENCIDOS
IMPORTACIÓN DE BIENES NOCIVOS PARA LA SALUD
USURA EN OPERACIONES DE FINANCIAMIENTO
CORRUPCIÓN ENTRE PARTICULARES
Los 3 primeros elementos sobrepasan el limire de mi spinner y no se visualiza el texto completo
el codigo de mi spinner es el siguente
[…] de los elementos de la lista desplegable y del control en sí, como ya explicamos en el artículo dedicado al […]