Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 23 di 97
  • livello avanzato
Indice lezioni

Spinner (menu a tendina)

Impariamo come creare il comune widget Spinner, utilizzato per la creazione dei menu a tendina all'interno di app mobile per Android.
Impariamo come creare il comune widget Spinner, utilizzato per la creazione dei menu a tendina all'interno di app mobile per Android.
Link copiato negli appunti

Lo spinner è un altro controllo molto comune, è il classico menu a tendina. In Android viene realizzato come AdapterView e tanto basta per farci comprendere il modo in cui dovremo usarlo.

Si è visto nelle lezioni precedenti che tutti gli AdapterView vengono grosso modo usati alla stessa maniera. È sufficiente collegare loro un Adapter che incapsula la logica di produzione delle View.

Per il resto l'AdapterView si occuperà di gestire gli eventi.

Spinner con valori fissi

Comunque lo Spinner trova la sua utilità anche in contesti meno complessi in cui si può usare come normale campo form per selezionare un valore in un dato insieme.

Pensiamo ad un form in cui si inseriscono i dati di una persona. Al momento di definire lo stato civile, la scelta ricade su un set di possibilità prestabilite: coniugato/a, divorziato/a, celibe/nubile, separato/a.

Il controllo ideale per effettuare questa scelta è senza dubbio lo Spinner . In questo caso, si potrebbe sentire meno il bisogno dell'Adapter in quanto la sorgente dati non cambierà più visto che vengono annoverati già tutti gli stati civili possibili.

In questo caso, si può procedere agendo solo tra risorse XML:

  • si crea un array di risorse stringa in un file della cartella res/values e lo si completa con tutti i valori necessari:
    <string-array name="staticivili">
    <item>Divorziato/a</item>
    <item>Separato/a</item>
    <item>Coniugato/a</item>
    <item>Celibe/Nubile</item>
    </string-array>
    La risorsa sarà accessibile in XML mediante @array/staticivili
  • nel file di layout in cui si trova lo Spinner si effettua una modifica. Si aggiunge l'attributo android:entries e gli si assegna la risorsa di stringhe a cui accedere:
    <Spinner
    android:id="@+id/spinner"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:entries="@array/staticivili"/>

Seguendo questi due semplici passi, nel layout troveremo lo spinner già popolato dei valori. Non è stato necessario apportare alcuna modifica nel codice Java e tantomeno istanziare direttamente un adapter.

Spinner con Adapter

Il comportamento dello Spinner legato ad un adapter è in buona parte uguale a quello della ListView e della GridView.

Vedremo ora un esempio che mostra un uso congiunto di Spinner e ListView in cui:

  • lo Spinner mostra un elenco di Paesi;
  • la ListView visualizza un elenco di città appartenenti tutte al Paese selezionato nello Spinner.

L'esempio ha anche il pregio di riepilogare molti concetti visti sinora nello studio delle GUI quindi lo si consideri un esercizio di validità generale.

L'immagine seguente mostra le varie fasi di funzionamento come appaiono in un emulatore.

FLe varie fasi di attività di uno spinner AndroidLe varie fasi di attività di uno spinner Android

La fonte dei dati sarà una classe Java, molto semplice, che con liste e mappe fornirà i dati necessari all'esempio:

public class CountryList
{
private HashMap<String,ArrayList<String>> list;
public CountryList()
{
list=new HashMap<String, ArrayList<String>>();
ArrayList<String> cities=new ArrayList<String>();
cities.add("Roma");
cities.add("Torino");
cities.add("Firenze");
list.put("Italia", cities);
cities=new ArrayList<String>();
cities.add("Parigi");
cities.add("Lione");
cities.add("Marsiglia");
list.put("Francia", cities);
cities=new ArrayList<String>();
cities.add("Madrid");
cities.add("Barcellona");
list.put("Spagna", cities);
}
public Collection<String> getCountries()
{
return list.keySet();
}
public Collection<String> getCitiesByCountry(String c)
{
return list.get(c);
}
}

Il layout dell'Activity è molto semplice (file: res/layout/activity_main.xml), un RelativeLayout che mostra entrambe le View:

<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">
<Spinner
android:layout_width="@dimen/body_width"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/margin_top_1"
android:id="@+id/countries"
/>
<ListView
android:layout_width="@dimen/body_width"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@+id/countries"
android:layout_marginTop="@dimen/margin_top_2"
android:id="@+id/cities"/>
</RelativeLayout>

mentre la forma che avrà la singola riga dello Spinner e della ListView sarà la seguente (file: res/layout/row.xml):

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="25sp"
android:id="@+id/rowtext" />

Tenere presente che quando nel codice dell'Activity richiameremo l'id R.id.rowtext ci riferiremo alla TextView compresa in questo layout.

Il codice dell'Activity non offre grandi sorprese:

public class MainActivity extends AppCompatActivity
{
    private CountryList countries=new CountryList();
    private ArrayAdapter<String> listviewAdapter;
    private ArrayAdapter<String> spinnerAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        // assegnazione del layout all'Activity
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // preparazione della ListView per l'elenco delle città
        ListView lv=findViewById(R.id.cities);
        listviewAdapter=new ArrayAdapter<String>(this, R.layout.row);
        lv.setAdapter(listviewAdapter);
        // preparazione dello Spinner per mostrare l'elenco dei Paesi
        spinnerAdapter=new ArrayAdapter<String>(this, R.layout.row);
        spinnerAdapter.addAll(countries.getCountries());
        Spinner sp= findViewById(R.id.countries);
        sp.setAdapter(spinnerAdapter);
        sp.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
        {
            @Override
            public void onItemSelected(AdapterView<?> arg0, View arg1,
                                       int arg2, long arg3) {
                TextView txt= arg1.findViewById(R.id.rowtext);
                String s=txt.getText().toString();
                updateCities(s);
            }
            @Override
            public void onNothingSelected(AdapterView<?> arg0)
            { }
        });
    }
    private void updateCities(String city)
    {
        ArrayList<String> l=(ArrayList<String>)
                countries.getCitiesByCountry(city);
        listviewAdapter.clear();
        listviewAdapter.addAll(l);
    }
}

Da notare comunque che:

  • essendo entrambi AdapterView, si sono svolte le stesse operazioni per Spinner e ListView. In entrambi si è preparato un Adapter che gli è stato collegato con il metodo setAdapter;
  • la gestione degli eventi è stata usata solo per lo Spinner. Avviene nella maniera classica illustrata nel capitolo delle View;
  • all'interno del metodo onItemSelected che gestisce la selezione di una voce dello Spinner viene invocato il metodo updateCities che aggiorna mediante l'adapter della ListView l'elenco delle città. Viene fatto in maniera molto semplice ricaricando una nuova lista.

Ti consigliamo anche