DevCorner: creiamo una ListView con layout custom

Giuseppe Tripodi
Giuseppe Tripodi Tech Master
DevCorner: creiamo una ListView con layout custom

Correva agosto dello scorso anno quando, sulle pagine del DevCorner, abbiamo parlato per la prima volta di ListView: sarebbe bello poter dire che tante cose sono cambiate e che oggi creare una ListView custom su Android è estremamente più semplice, ma non vogliamo mentirvi.

LEGGI ANCHE: DevCorner: creiamo una Listview, aggiungiamo ed eliminiamo elementi

Per questo motivo, oggi abbiamo deciso finalmente di affrontare l'argomento e trattare la creazione di una lista di elementi partendo da un layout customizzato.

Se nell'introduzione vi abbiamo spaventato, non era nostra intenzione: la verità è che creare una ListView personalizzata non è poi così difficile, ma semplicemente un'operazione relativamente noiosa che non risulta di immediata comprensione alla maggior parte dei novelli programmatori.

Supponiamo, quindi, di voler riprendere l'idea di piazzare (alcuni) degli autori di AndroidWorld in una lista, con foto e ruolo: la prima cosa da fare è creare un layout personalizzato che rappresenterà l'aspetto di ogni singola riga della lista.

Per farlo, creiamo un nuovo file XML e posizioniamo un'Imageview all'estrema sinistra, una TextView per il nome in alto e una seconda TextView più piccola per il ruolo.

<relativelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content">

<imageview android:id="@+id/immagine" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignparentleft="true" android:layout_alignparenttop="true" android:src="@drawable/ic_launcher"></imageview>

<textview android:id="@+id/nome" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignbottom="@+id/immagine" android:layout_marginleft="48dp" android:layout_torightof="@+id/immagine" android:text="nome" android:textappearance="?android:attr/textAppearanceLarge" android:text></textview>

<textview android:id="@+id/ruolo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/nome" android:layout_alignleft="@+id/nome" android:text="ruolo" android:textappearance="?android:attr/textAppearanceSmall"></textview>

</relativelayout>

A questo punto, la cosa più logica da fare (sebbene non tutti seguano questa procedura) è modellare una classe di tipo Autore che avrà una String per il nome, un'int che corrisponde all'id dell'immagine che abbiamo precedentemente copiato nei Drawable e, infine, un'altra stringa con il ruolo.

Scriviamo anche il costruttore e i vari getter e setter, poiché questa classe ci servirà d'appoggio per istanziare oggetti di tipo Autore da piazzare nella lista.

public class Autore {
	String nome;
	int idImmagine;
	String ruolo;

	public Autore(String nome, int idImmagine, String ruolo) {
		super();
		this.nome = nome;
		this.idImmagine = idImmagine;
		this.ruolo = ruolo;
	}
	public String getNome() {
		return nome;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}
	public int getIdImmagine() {
		return idImmagine;
	}
	public void setIdImmagine(int idImmagine) {
		this.idImmagine = idImmagine;
	}
	public String getRuolo() {
		return ruolo;
	}
	public void setRuolo(String ruolo) {
		this.ruolo = ruolo;
	} 
}

Adesso abbiamo l'aspetto estetico che avrà il nostro elemento autore così come la classe Java che lo rappresenta: non rimane che creare un Adapter che "sistemi" ogni oggetto di tipo Autore che creiamo all'interno della lista. Per farlo creiamo una classe MyAdapter che estende il BaseAdapter, ossia l'adapter di default utilizzato da Android. Aggiungiamo i metodi di cui ci chiederà di fare l'Override e creiamo il costruttore, al quale dobbiamo passare l'Activity dove è contenuta la ListView e un ArrayList di Autori.

Fatto questo, andiamo a modificare il metodo getView, che si occupa di restituire le singole riga della lista riempita.

Menzione a parte merita l'elemento Inflater, che è l'oggetto che si occupa di riempire la nostra ListView utilizzando come layout per la righa il file XML row che abbiamo creato all'inizio; visto che non abbiamo esigenze estreme, utilizzeremo l'inflater di default di Android.
Tornanto al metodo getView, passiamo all'inflater la nostra row personalizzata, prendiamo dalla lista degli autori quello alla posizione corrente e, dopo aver identificato TextView e ImageView della row, settiamo i dettagli relativi all'oggetto Autore analizzato.

public class MyAdapter extends BaseAdapter{

	private Activity mActivity;
	private ArrayList listaAutori;
	private static LayoutInflater inflater = null;

	public MyAdapter(Activity a, ArrayList list) {
		mActivity = a;
		listaAutori = list;
		inflater = (LayoutInflater) mActivity
				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return listaAutori.size();
	}

	@Override
	public Object getItem(int item) {
		// TODO Auto-generated method stub
		return item;
	}

	@Override
	public long getItemId(int item) {
		// TODO Auto-generated method stub
		return item;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		View vi = convertView;
		if (convertView == null)
			vi = inflater.inflate(R.layout.row, null);

		TextView nome = (TextView) vi.findViewById(R.id.nome);
		TextView ruolo = (TextView) vi.findViewById(R.id.ruolo);
		ImageView profilo = (ImageView) vi.findViewById(R.id.immagine);
		Autore autoreCorrente = listaAutori.get(position);
		nome.setText(autoreCorrente.getNome());
		ruolo.setText(autoreCorrente.getRuolo());
		profilo.setImageDrawable(mActivity.getResources().getDrawable(autoreCorrente.getIdImmagine()));
		// TODO Auto-generated method stub
		return vi;
	}

}

Non ci rimane, infine, che vedere cosa fare nella nostra MainActivity: dopo aver dichiarato un ArrayList di Autori, riempiamolo con qualche membro del team di AndroidWorld (quattro per l'esattezza, perché siamo programmatori e di conseguenza pigri).

Fatto questo, identifichiamo la nostra ListView dall'ID e, dopo aver dichiarato un nuovo oggetto di tipo MyAdapter, utilizziamolo per riempire la nostra lista.

public class MainActivity extends Activity {
	ListView listaAutori;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		ArrayList autori = new ArrayList();
		autori.add(new Autore("Emanuele Cisotti", R.drawable.cisotti, "Amministratore"));
		autori.add(new Autore("Nicola Ligas", R.drawable.ligas, "Editor"));
		autori.add(new Autore("Giuseppe Tripodi", R.drawable.tripodi, "Autore"));
		autori.add(new Autore("Roberto Orgiu", R.drawable.orgiu, "Autore"));
		listaAutori = (ListView) findViewById(R.id.listView);
		MyAdapter madapter = new MyAdapter(this, autori);
		listaAutori.setAdapter(madapter);

	}

Come avete visto, utilizzare i layout personalizzati nelle ListView non è niente di impossibile, anzi: la difficoltà iniziale sta solo nello gestire gli adapter e capire come utilizzarli ma imparato questo tutto il resto viene automaticamente. Anche per questa settimana l'appuntamento con DevCorner è terminato: potete trovare il codice sorgente dell'applicazione d'esempio sul nostro forum, dove ovviamente potrete eventualmente approfittare per chiedere aiuto.

Via: DevCorner