====== 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". \\