Android List Adapters

Adapters

Los ListAdapters son los que saben como pintar los elementos de una lista, estas listas pueden ser tanto un ListView, Spinner List, Pager y demás elementos que sean de tipo de iteraciones o listas en si.

El rol de los adapters es encargarse de saber como pintar cada elemento de una lista al igual que se encargan de manejar la data que mostrara la misma.

ListView

Trabajar con listas en android es super importante y ademas es bien necesario a la hora de mostrar data, siempre tendremos la necesidad de mostrar una lista de elementos de un mismo tipo.

Ejemplo ListView Simple

View

        <ListView
            android:layout_width="fill_parent"
            android:id="@+id/simple_list"
            android:layout_weight="1"
            android:layout_height="wrap_content"/>

En nuestra actividad referenciamos nuestra simple_list

        //Lista simple
        ListView simple = (ListView)findViewById(R.id.simple_list);

Para una lista simple podemos usar directamente un ArrayAdapter y de layout simple_list_item_1 terminaríamos con algo como esto

        //Lista simple
        ListView simple = (ListView)findViewById(R.id.simple_list);

        //creamos nuestro data source
        String[] dias = new String[]{"Lunes","Martes","Miércoles","Jueves","Viernes","Sabado"};

        //instanciamos nuestro adaptador
        ListAdapter simpleAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,dias);

        simple.setAdapter(simpleAdapter);

El resultado seria algo como esto

[Imagen Lista simple]

En caso de que nuestra aplicación requiera algo mas que una lista con simple texto y poder tener el control sobre cada una de las filas necesitamos tener nuestro propio ArrayAdapter, algo como esto.

Nuestra entidad que manejaremos, en este caso usare una clase llamada Evento:

public class Evento {
    private String titulo;
    private String detalles;

    public Evento(String titulo, String detalles) {
        this.titulo = titulo;
        this.detalles = detalles;
    }

    public String getTitulo() {
        return titulo;
    }

    public void setTitulo(String titulo) {
        this.titulo = titulo;
    }

    public String getDetalles() {
        return detalles;
    }

    public void setDetalles(String detalles) {
        this.detalles = detalles;
    }
}

Para implementar array adapter necesitamos un template que sera utilizado como molde para pintar cada una de las filas de nuestra lista en base a la cantidad de elementos que estemos agregando a nuestro adapter.

Item template:

Este item template no es mas que un layout cualquiera, solo que hay que tener en cuenta que sera usado para una lista y hay que tener bien en cuenta su tamaño para lograr lo que se quiere.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:layout_width="wrap_content"
        android:src="@drawable/ic_launcher"
        android:id="@+id/imagen_evento"
        android:layout_margin="12dp"
        android:layout_height="wrap_content" />

    <TextView
        android:layout_toRightOf="@+id/imagen_evento"
        android:layout_width="wrap_content"
        android:layout_margin="12dp"
        android:id="@+id/titulo"
        android:text="Titulo"
        android:layout_height="wrap_content" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_toRightOf="@+id/imagen_evento"
        android:layout_below="@+id/titulo"
        android:id="@+id/detalles"
        android:layout_margin="12dp"
        android:text="Detalles"
        android:layout_height="wrap_content" />

</RelativeLayout>

Luego nuestra implementación de ArrayAdapter:

public class EventoAdapter extends ArrayAdapter<Evento> {

    private Context context;
    private int itemLayout;

    public EventoAdapter(Context context, int resource, Evento[] objects) {
        super(context, resource, objects);

        this.context = context;
        this.itemLayout = resource;
    }

    public EventoAdapter(Context context, int resource) {
        super(context, resource);

        this.context = context;
        this.itemLayout = resource;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View rootView = convertView;

        if(rootView == null){
            LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            rootView = inflater.inflate(itemLayout,null);
        }

        Evento item = getItem(position);

        TextView titleView = (TextView)rootView.findViewById(R.id.titulo);
        TextView detallesTxt = (TextView)rootView.findViewById(R.id.titulo);

        titleView.setText(item.getTitulo());
        detallesTxt.setText(item.getDetalles());

        return  rootView;
    }
}

Linea por Linea:

Tenemos que extender de ArrayAdapter y parametrizarlo con el tipo de objetos que estará manejando nuestro adapter

public class EventoAdapter extends ArrayAdapter<Evento>

Luego hay que sobre escribir este metodo getView de la clase ArrayAdapter, en este metodo es donde instanciamos las vistas y poblamos la vista con la data a mostrar.

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ....
    }

El objetivo del metodo getView es simplemente retornar un View hago esta salvedad para referirme a que sus rows no necesariamente deben tener el mismo layout todas.

Ya luego lo que hacemos es inflate el layout que estamos usando para nuestra lista, obtenemos el item actual Evento item = getItem(position); y seteamos nuestra vista con dicha data.

        View rootView = convertView;

        if(rootView == null){
            LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            rootView = inflater.inflate(itemLayout,null);
        }

        Evento item = getItem(position);

        TextView titleView = (TextView)rootView.findViewById(R.id.titulo);
        TextView detallesTxt = (TextView)rootView.findViewById(R.id.titulo);

        titleView.setText(item.getTitulo());
        detallesTxt.setText(item.getDetalles());

Si realizamos todo bien tendríamos algo como esto:

Para crear un spinner List es casi la misma via, la unica diferencia es que en nuestro Adapter tendremos que agregar un metodo mas.

Spinner List

<Spinner
    android:id="@+id/test_spinner"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />

MainActivity.java


Spinner spinner = (Spinner) findViewById(R.id.test_spinner);

ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(this,android.R.layout.simple_list_item_1,dias);

spinner.setAdapter(adapter);

Esto nos funcionara y tendremos un SpinnerList funcional, ahora si quiero que mis items del SpinerList tengas un layout diferente podría ( y voy a usar) el mismo adapter que use en el ejemplo anterior.

Para terminar de implementar el adapter y hacerlo util para un SpinnerList es necesario implementar este metodo «getDropDownView»

@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
    return ..
}

Este metodo al igual que «getView» retornan una vista; si observan notaran que ambos metodos tienen la misma firma, por lo que podríamos reutilizar lo que ya hacemos en «getView» en caso de que ambos layouts sean lo mismo.

@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
    return this.getView(position,convertView,parent);
}

Referencia

Codigo fuente
ListAdapter
ListView Android Developer
SpinnerView Android Developer