Category Archives: Android

Personalizando el ListView de Android

English

El siguiente documento describe como personalizar el ListView de android. En este caso, se modificara el ListView para desplegar 2 filas y una imagen.

Las siguientes librerias y programas fueron utilizados:

– Windows 7

– Eclipse Galileo (Android DDMS, Android Development Tools)

1.1) Primero, se crea un nuevo proyecto de Android en Eclipse:

image_thumb

1.2) Puedes utilizar cualquier nombre para el proyecto, en mi caso, lo llame CustomListView. La version de Android es la 2.3, pero debe funcionar sin problemas con versiones anteriores. En la seccion de ‘Properties’, se debe de incluir el nombre de la aplicacion, la libreria (package) y la actividad. Estos campos se llenaron de la manera siguiente: Custom ListView, com.customlv.test, LVMain.

image

Si se desea relacionar un proyecto de pruebas al codigo actual, se da clic en NEXT, en caso contrario, selecciona FINISH.

1.3) Eclipse, de manera automatica, crea un esqueleto para una aplicacion de Android, incluyendo el archivo AndroidManifest. Lo siguiente que se debe actualizar es el layout de la actividad (res->layout->main.xml) y agregar los componentes que necesitamos para este ejercicio, ImageView and TextView:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="6dip">
    <ImageView
        android:id="@+id/myimage"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:layout_marginRight="6dip"/>
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="0dip"
        android:layout_weight="1"
        android:layout_height="fill_parent">
        <TextView android:id="@+id/line1"
            android:layout_width="fill_parent"
            android:layout_height="0dip"
            android:layout_weight="1"
            android:gravity="center_vertical"/>
        <TextView android:id="@+id/line2"
            android:layout_width="fill_parent"
            android:layout_height="0dip"
            android:layout_weight="1"
            android:singleLine="true"
            android:ellipsize="marquee"/>
    </LinearLayout>
</LinearLayout>

1.4) Los datos del componente  ListView provienen de un objeto de tipo Adapter. Hay diferentes tipos de Adapters (ArrayAdapter, CursorAdapter, etc) y todos ellos extienden de una clase base llamada  BaseAdapter. Para personalizar nuestro componente ListView, es necesario crear un adaptador; para esto, agregaremos una nueva clase a nuestro proyecto llamada MyCustomAdapter:

image

Existen 4 metodos que deben ser implementados:

  • getCount: Regresa el total de objetos listados por el listView.
  • getItem: Regresa un objeto, tomando como base un indice.
  • getItemId: Regresa el ID de la fila seleccionada.
  • getView: Regresa un objeto de tipo View.

1.5) Hay 2 componentes adicionales que deben ser agregados a este codigo: el Layout inflater y una coleccion para almacenar los objetos que seran desplegados (o bien, puede ser un objeto de tipo Cursor, si los valores vienen de una base de datos). El LayoutInflater actua como puente entre el XML del laout y los objetos de tipo View. La coleccion (en este caso un ArrayList) guarda los items u objetos que seran agregados al listView. Durante la declaracion del objeto MyCustomAdapter, el inflater asociado al contexto sera referenciado por nuestro CustomAdapter y los datos seran pasados al layout.

public class MyCustomAdapter extends BaseAdapter {

	private LayoutInflater li;
	private List<User> users = new ArrayList<User>();

	public MyCustomAdapter(Context context, List<User> items)
	{
		li = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		if(items != null)
			users = items;
	}

....

Para este ejemplo, usare como entrada para el ListView una lista de objetos de tipo User. El codigo de esta clase se presenta mas adelante.

1.6) Los primeros 3 metodos (getCount, getItem, getItemId) se implementan de la siguiente manera:
....
  @Override
	public int getCount() {
		return users.size();
	}

	@Override
	public Object getItem(int position) {
		return users.get(position);
	}

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

....

Los valores que regresan estos metodos estan basados en el objeto List que se recibe como entrada.El primer metodo regresa el numero de items almacenados en la coleccion; la funcion getItem, regresa el objeto guardado en el indice recibido como entrada. Por ultimo, el metodo getItemId, regresa el mismo valor que es recibido como entrada (este valor seria el numero de la fila que fue seleccionada).

1.7) Despues, se define el metodo getView. Este metodo hace todo el trabajo relacionado con el ListView ya que convierte cada item en un objeto de tipo View:

...
@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		//current view object
		View v = convertView;

		final User user = users.get(position);

		//if View exists, then reuse... else create a new object.
		if (v == null) {
			v = li.inflate(com.customlv.test.R.layout.main, null);
		}

		//reference to the ImageView component
		final ImageView mLogo = (ImageView)v.findViewById(com.customlv.test.R.id.myimage);

		//if gender is male, then use 'male' icon. Otherwise, female.
		if(user.getSex().equals("male"))
			mLogo.setImageResource(com.customlv.test.R.drawable.male);
		else
			mLogo.setImageResource(com.customlv.test.R.drawable.female);

		//set 'name' in line 1.
		final TextView nameTv = (TextView) v.findViewById(com.customlv.test.R.id.line1);
		nameTv.setText(user.getName());

		//set 'gender' in line 2.
		final TextView genderTv = (TextView) v.findViewById(com.customlv.test.R.id.line2);
		genderTv.setText(user.getSex());

		return v;
	}
...

El metodo recibe como entrada un objeto View; Si este ya esta instanciado, entonces se reutiliza; en caso contrario, se declara un nuevo objeto de tipo View. El ListView desplegara 2 imagenes diferentes, estas dependen del sexo del usuario.

1.8) A continuacion se define el tipo de objetos que seran consumidos por nuestro  ListView. Para esto, hay que agregar una nueva clase llamada User y definirla de la siguiente manera:

public class User {

	private String name;
	private String sex;

   public User(){}

	public User(String name, String sex)
	{
		setName(name);
		setSex(sex);
	}

	public String getName() {
		return name;
	}
	public String getSex() {
		return sex;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}

}

1.9) Por ultimo, probamos nuestro listView. Regresamos a la actividad principal  (LVMain) y agregamos el siguiente codigo:

public class LVMain extends ListActivity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        List<User> users = new ArrayList<User>();
        users.add(new User("john", "male"));
        users.add(new User("mary","female"));
        users.add(new User("bob","male"));

        setListAdapter(new MyCustomAdapter(this, users));
    }
}

1.10) Corremos la aplicacion en el emulador y debemos ver algo como esto:

image