====== Android Spinner o Dropdown ======
Un //spinner// d'Android és un //widget// (element gràfic) que habitualment coneixem en altres entorns com a //dropdown menu//, selector o menú desplegable.
La programació en Android és, però, més complicada que en altres entorns degut a la gestió de la RAM en llistes molt llargues amb recursos costosos com les imatges, explicat a l'article [[Android ListView]].
{{ https://developer.android.com/static/images/ui/spinner.png?250 }}
{{tag> #FpInfor #Dam #DamMp08 #DamMp08Uf1 android spinner dropdown menu desplegable}}
\\
===== Coneixements previs =====
Cal conèixer [[Android]].
\\
===== Creació d'un spinner de forma gràfica =====
Sempre convé començar per la pàgina oficial d'Android, en aquest cas sobre [[https://developer.android.com/guide/topics/ui/controls/spinner|Spinners]].
L'exemple és un //Spinner// amb una llista fixa dels planetes. El què es fa primerament és definir la llista de planetes com a ''Resource'' (el famós ''R'' d'Android).
A la pàgina oficial ens mostra la manera d'enllaçar el ''Spinner'' amb un ''ArrayAdapter''. Això resulta complexe i està pensat per a situacions molt genèriques en què les dades poden ser dinàmiques, com per exemple si surten d'una consulta a una base de dades. Si volem saber més d'aquesta opció, ho podem investigar a l'article [[Android ListView]], que utilitza ''Adapters'' de forma molt similar.
Però nosaltres volem un //dropdown// senzill, i per tant ho farem més simple, assignant la llista de valors al control i llestos. Hi ha molts casos que cal això i no necessita la complexitat de l'Adapter.
- Crea una nova app amb ''EmptyActivity''.
- Crea el ''Spinner'' dins el //layout// de la ''MainActivity'' (per exemple, arxiu ''activity_main.xml''). Ho podem fer de forma gràfica.
- Crear la [[https://developer.android.com/guide/topics/ui/controls/spinner#Populate|llista de planetes que diu l'article del Spinner]].
- Assignem el valor de l'array de planetes al ''Spinner''.
- En el codi, poder recollir el valor del Spinner amb String text = mySpinner.getSelectedItem().toString();
- Posa un botó que quan el premis reculli el valor del ''Spinner'' i el mostri en un ''Toast''.
\\
===== Creació d'un Spinner de forma programàtica =====
==== A partir de dades d'un resource ====
Primer caldrà crear un **array d'elements a l'arxiu ''strings.xml''** (gràficament al Android Studio).
Per exemple, per fer un selector de números del 0 al 5:
- 0
- 1
- 2
- 3
- 4
- 5
Es pot crear un Spinner de forma programàtica amb el seu ''Adapter'' d'aquesta manera:
Spinner spinner = new Spinner(this);
ArrayAdapter adapter = ArrayAdapter.createFromResource(this,
R.array.nombres, android.R.layout.simple_spinner_item);
spinner.setAdapter(adapter);
\\
==== A partir de dades dinàmiques ====
Per crear un rang de dades del 0 al 5 com hem fet abans no cal definir el array a l'arxiu XML, que seria estàtic perquè no es podria modificar en temps d'execució. En canvi, es pot generar el ''Spinner'' així:
Spinner spinner = new Spinner(this);
CharSequence[] nombres = {"0","1","2","3","4","5"};
ArrayAdapter adapter = new ArrayAdapter(this,
android.R.layout.simple_spinner_item, nombres);
spinner.setAdapter(adapter);
\\
===== Connectant les callback dels Spinner =====
Per poder respondre a les accions de l'usuari al canviar els valors dels ''Spinner'' necessitarem implementar les //callback// pertinents. L'objecte que sol fer la feina és un ''Listener''.
Tindrem 2 estratègies bàsiques per a implementar les //callback// d'un ''Spinner'' (o de qualsevol ''View'' amb acció. Convé conèixer les dues, encara que recomanem la segona.
==== Opció 1: objecte OnItemSelectedListener ====
Crear un objecte tipus ''OnItemSelectedListener'' per a cada Spinner, similarment a com solem fer amb els ''OnClickListener'' dels ''Button'':
Spinner spinner = new Spinner(this);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> adapterView, View view, int i, long l) {
// la posició del spinner és 'i', però també es pot buscar amb
String string = spinner.getSelectedItem().toString();
}
@Override
public void onNothingSelected(AdapterView> adapterView) {
}
});
==== Opció 2: heretar OnItemSelechtedListener a la MainActivity ====
Podem heretar la interfície ''OnItemSelectedListener'' a la pròpia ''MainActivity'' i implementant les funcions necessàries com a mètodes d'aquesta, tal i com suggereix la [[https://developer.android.com/develop/ui/views/components/spinner#SelectListener|doc oficial del Spinner]].
public class SpinnerActivity extends Activity implements OnItemSelectedListener {
...
protected void onCreate(Bundle savedInstanceState) {
...
Spinner spinner = new Spinner(this);
spinner.setOnItemSelectedListener(this);
...
}
public void onItemSelected(AdapterView> parent, View view,
int pos, long id) {
// An item was selected. You can retrieve the selected item using
// parent.getItemAtPosition(pos)
}
public void onNothingSelected(AdapterView> parent) {
// Another interface callback
}
}
Ens resultarà un codi més llegible si fem servir la opció 2, al menys en aquest cas.
Segueix la [[https://developer.android.com/develop/ui/views/components/spinner#SelectListener|doc oficial del Spinner]] on l'exemple segueix aquesta estratègia implementant les //callback//. Tant en un cas com a l'altra cal implementar les dues funcions:
* ''onItemSelected'': és on activarem la lògica del nostre joc.
* ''onNothingSelected'': és obligatoria implementar-la, però segurament no hi posarem res de codi.
\\
===== Exercicis =====
Crea una app amb 2 ''Spinner'':
* Un creat de forma estàtica amb els noms dels planetes, tal i com planteja la doc oficial de ''Spinner''.
* Un creat programàticament amb els números descrits anteriorment.
Implementa les //callback// necessàries fent que quan es canvii el valor d'un ''Spinner'' ens mostri un ''Log'' indicant-nos el text "Spinner modificat".
\\