Items personalizados para un ListView en Android

Buenas, hace tiempo que ya hicimos algún ejercicio de descarga de información, pero me quedaba por hacer algún ejemplo un poco más complejo para poder tratar esa información y utilizarla por ejemplo en un ListView.



El elemento ListView de Android permite de una forma muy simple asociar una fuente de datos como una consulta de SQLite con una determinada estructura y este lo rellenará de una forma standard. Pero nosotros no queremos hacer las cosas de forma standard, entre otras cosas porque nunca nos piden las cosas de forma standard.


Bueno, vamos a empezar por definir como queremos que se vean cada uno de los items de nuestro ListView, para ello vamos a crear un layout que llamaremos item_list.xml. Aquí lo haremos muy simple, pero luego se puede complicar todo lo que se quiera. Veamos como queda:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical"> 
 <TextView android:layout_width="fill_parent"android:layout_height="wrap_content" android:id="@+id/lblTitulo" />
 <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/lblDescripcion" />
</LinearLayout>


Como veis, únicamente tiene dos elementos TextView, uno para un título y otro para una descripción. Se podría añadir cualquier cosa, botones, checkbox, imagenes...
Una vez hecho esto vamos a crear una clase que se encargue del funcionamiento de esta plantilla a la que llamaremos ItemList y heredará de LinearLayout.



public class ListItem extends LinearLayout  {
 
 private TextView lblTitulo, lblDescripcion;
        private Libro libro; 
 
 public ListItem(Context context, Libro libro) {
  super(context);
                this.libro = libro;
  inicializar();
 }
 
 private void inicializar(){
  String infService = Context.LAYOUT_INFLATER_SERVICE;
  LayoutInflater li = (LayoutInflater)getContext().getSystemService(infService);
  li.inflate(R.layout.item_list, this, true);
  
  lblTitulo = (TextView) findViewById(R.id.lblTitulo);
  lblDescripcion = (TextView) findViewById(R.id.lblDescripcion);

  
  lblTitulo.setText(libro.getTitulo());
  lblDescripcion.setText(libro.getDescripcion());
 }
}


Como veis es una clase muy simple. En su constructor le pasamos un objeto tipo Libro que definimos más adelante ya que esta clase se va a encargar de mostrar el item de un libro. En el método inicializar después de hacer un inflate de nuestro layout accedemos a los TextView y seteamos su valor mediante los valores del objeto libro. Como dije antes se puede añadir por ejemplo un botón y en inicializar se podría darle valor a su evento click por ejemplo.

Ahora veamos como se vería la clase Libro. Está lo más simplificada posible, únicamente con el título y la descripción que es lo que necesitamos.
public class Libro {

 private String titulo;
 private String descripcion;
 
 public void setTitulo(String titulo) {
  this.titulo = titulo;
 }
 public String getTitulo() {
  return titulo;
 }
 public void setDescripcion(String descripcion) {
  this.descripcion = descripcion;
 }
 public String getDescripcion() {
  return descripcion;
 }
 
}


Seguimos avanzando, ahora que ya tenemos una plantilla para los items y una forma de rellenar cada uno de estos items, necesitamos definir un adaptador que intermedie entre los items y el ListView para ello vamos a crear otra clase que se llamará ItemListAdapter y va a heredar de BaseAdapter. BaseAdapter nos da las herramientas necesarias para interactuar con cualquier objeto que maneje listas de datos y mostrarlos en un ListView, GridView, Gallery...

Esta clase ItemListAdapter va a recibir una lista de objetos Libro que se encargará de manejar. Veamos como lo hace:


public class ItemListAdapter extends BaseAdapter {

 private Activity activity;
 private List<Libro> listLibros;
 
 
 public ItemListAdapter(Activity activity, List<Libro> listLibros){
  this.activity = activity;
  this.listLibros = listLibros;  
 }
 
 public int getCount() {
  return listLibros.size();
 }

 public Object getItem(int position) {
  return listLibros.get(position);
 }

 public long getItemId(int position) {  
  return position;
 }

 public View getView(int position, View convertView, ViewGroup parent) {
  
  ListItem lstItem = new ListItem(activity, listLibros.get(position) );  
  
  return lstItem;
 }

}

Nuestro adaptador es muy simple, la parte más importante está en el método
getView. En este método se va a devolver un objeto View (o cualquiera que herede de él), así que podemos crear cualquier objeto como una imagen, un LinearLayout con más elementos o lo que se os ocurra y el ListView se encargará de mostrarlo como un item más. En nuestro caso estamos creando una instancia de nuestro objeto ListItem. El item correspondiente de nuestra lista de libros nos lo da el parámetro position y con el accedemos al objeto de tipo List<Libro>.

Destacar también el método
getItemId. Como tenemos que devolver un dato tipo long y la clase Libro no tiene una propiedad de este tipo devuelvo la posición, pero si existiera un identificador numérico se podría acceder con el método get de List.

Ahora que ya tenemos todo listo vamos a crear un layout donde mostrar el ListView y una Activity donde veremos como usar todo esto. Lo primero es el layout, le llamaremos
list.xml.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  android:layout_width="fill_parent" android:layout_height="wrap_content">
<ListView android:id="@+id/list" android:layout_width="fill_parent" android:layout_height="wrap_content">
</ListView>
</LinearLayout>


También muy simple, un LinearLayout y dentro un ListView. Ahora en el onCreate de nuestra Activity (o donde lo necesiteis) rellenamos un objeto List con libros y lo mostraremos en el ListView.



private ListView list;
private ItemListAdapter adapter;
private List<Libro> listLibros;
@Override
    public void onCreate(Bundle savedInstanceState)  {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.list);        
        list = (ListView) findViewById(R.id.list);
listLibros = new ArrayList<Libro>();
Libro libro;
//Aqui rellenamos solo con un libro, pero se puede descargar una lista de internet o leyendo de base de datos por ejemplo.
libro = new Libro();
Libro.setTitulo("titulo");
Libro.setDescripcion("descripcion");
listLibros.add(libro);

//Ahora rellenamos el ListView
adapter = new ItemListAdapter(this, listLibros);
list.setAdapter(adapter);
//Posteriormente podemos añadir más items a nuestro listview de la siguiente forma

//primero añadimos más objetos a nuestra lista
libro = new Libro();
Libro.setTitulo("titulo 2");
Libro.setDescripcion("descripcion 2");
listLibros.add(libro);

//y luego le decimos a nuestro adapter que notifique los cambios correspondientes y que actualice los items del ListView
adapter.notifyDataSetChanged();

}


Lo primero a destacar es la forma de rellenar la lista de libros, aquí se hace de forma manual pero ya hemos visto como acceder a datos a través de un servicio web o mediante base de datos.

Empezamos como siempre, accediendo al layout que tiene nuestro ListView y haciendo referencia a él con el objeto list. Luego inicializamos listLibros y añadimos los libros, en este caso de forma manual.

Una vez rellenada la lista inicializamos en adapter un ItemListAdapter pasándole la Activity y la lista de libros, y por último seteamos el adaptador de nuestro ListView con nuestro ItemListAdapter.

Hay veces que no tenemos todos los datos para el ListView y se van añadiendo más datos posteriormente. Actualizar el ListView en este caso es muy fácil. Simplemente añadiríamos en este caso más libros a nuestra lista de Libros y luego le decimos a nuestro ItemListAdapter que se han producido cambios y que debe actualizarlos mediante el método notifyDataSetChanged.

Comments are closed.