---
title: Expansión al ListView o listado en Android
url: https://jarroba.com/expansion-listview/
author: Ramón Invarato
date: 2013-05-25
modified: 2017-06-02
language: es
license: CC BY-NC-SA 3.0 (https://creativecommons.org/licenses/by-nc-sa/3.0/) — attribution: "Expansión al ListView o listado en Android", Ramón Invarato, jarroba.com
categories: Aplicaciones Móviles
---

# Expansión al ListView o listado en Android

En respuesta a las dudas más frecuentes sobre Listados en Android y en ampliación de lo aprendido. Recopilamos en este artículo la solución a las preguntas más comunes que nos han hecho los lectores aquí mismo o en el artículo [https://jarroba.com/listview-o-listado-en-android/](https://jarroba.com/listview-o-listado-en-android/) . Notar que en este artículo emplearemos como base el ejemplo de listado descrito en detalle en el [anterior artículo](https://jarroba.com/listview-o-listado-en-android/). Por lo que es necesario que entiendas como funciona un listado personalizado en Android antes de continuar.

 

## **GridView personalizado en Android en vez de una ListView**

 

Si te preguntas ¿Cómo hacer un GridView en Android con las casillas personalizadas? pues queremos los datos colocados en forma de mosaico. Vemos una imagen de ejemplo a continuación:

 

[![GridView en Android - www.jarroba.com](https://jarroba.com/wp-content/uploads/2013/05/GridView-en-Android-www.jarroba.com_.png)](https://jarroba.com/wp-content/uploads/2013/05/GridView-en-Android-www.jarroba.com_.png)

 

Además, nos interesa que puedan pulsar las teselas, para poder controlar lo que ocurra con ellas.

 

[![GridView que pueda ser pulsado - www.jarroba.com](https://jarroba.com/wp-content/uploads/2013/05/GridView-que-pueda-ser-pulsado-www.jarroba.com_.png)](https://jarroba.com/wp-content/uploads/2013/05/GridView-que-pueda-ser-pulsado-www.jarroba.com_.png)

 

Antes de seguir, es hora de que conozcas un pequeño secreto: ya sabes cómo se hace esto. Jarroba te ha metido el conocimiento de GridView a la fuerza y no te has dado ni cuenta 🙂 ¿Cómo es esto posible? Porque se hacen de la misma manera tanto un ListView como un GridView, y el adaptador que te hemos mostrado está preparado para esto.

 

Del ejemplo del listado no necesitaremos cambiar nada de la lógica de Java (lo único que cambiaremos en Java será las dos veces que aparece ListView por GridView, lo enseñamos un poco más adelante). Realmente, el GridView, es un listado con otra representación gráfica de los elementos. Es completamente lo mismo, lo que cambian son las vistas (es decir, los ficheros xml de “listado.xml” y “entrada.xml”)

 

Respetamos los mismos nombres que en el ejemplo principal del listado –puedes cambiarlos o dejarlos, aquí los dejaré por no cambiar código más de lo estrictamente necesario. Donde antes había un listado queremos un listado en forma de mosaico. Para ello modificamos como sigue **list****ado.xml:**

 

```

<?xml version="1.0" encoding="utf-8"?>

<GridView xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/ListView_listado"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:numColumns="3" >

</GridView>
```

 

En este ejemplo respetamos los datos de cada fila y los colocamos en cada tesela. Modificaremos a nuestro gusto la tesela. En nuestro ejemplo queda de la siguiente manera **entrada.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="fill_parent"

android:orientation="vertical"

android:padding="5dp" >

<TextView

android:id="@+id/textView_superior"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:maxLines="1"

android:text="Large Text"

android:textAppearance="?android:attr/textAppearanceMedium" />

<FrameLayout

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:gravity="center"

android:orientation="vertical" >

<ImageView

android:id="@+id/imageView_imagen"

android:layout_width="100dp"

android:layout_height="100dp"

android:layout_gravity="center"

android:adjustViewBounds="true"

android:contentDescription="Descripción del contenido de la imagen"

android:scaleType="fitXY"

android:src="@android:drawable/ic_menu_gallery" />

<TextView

android:id="@+id/textView_inferior"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center"

android:maxLines="4"

android:text="Small Text"

android:textAppearance="?android:attr/textAppearanceSmall"

android:textColor="@android:color/white"

android:textStyle="bold" />

</FrameLayout>

</LinearLayout>
```

 

Solo nos queda cambiar dos palabras del **MainActivity.java.**Solo hay que sustituir ListView por GridView, tanto en la variable global, que quedaría así:

 

```

private GridView lista;
```

 

Como en la declaración de la variable, que quedaría como sigue:

 

```

lista = (GridView) findViewById(R.id.ListView_listado);
```

 

Como puedes comprobar por ti mismo: ya sabías hacerlo 😀

 

 

## **Spinner personalizado en Android**

 

El Spinner (se suele conocer en otros lenguajes por ComboBox, cuadro de selección o extensible, etc) se comporta de igual manera que el GridView o el ListView. A grandes rasgos, el Spinner es un listado de elementos. Indicar que aquí explicaremos como personalizar los elementos de un Spinner, si lo que buscamos es el Spinner básico, tenemos un ejemplo completo en: [http://developer.android.com/guide/topics/ui/controls/spinner.html](http://developer.android.com/guide/topics/ui/controls/spinner.html)

 

Para el ejemplo queremos que el usuarios pueda seleccionar una y solo una de los aves que tenemos. Como es lógico, siempre habrá un elemento seleccionado, aunque carguemos por primera vez la actividad (este primer elemento normalmente es el típico de "seleccione una opción", aquí por simplificar usaremos el primero introducido, que es el "Buho"); por eso en la imagen se lanza el toast de que se ha seleccionado, es el tratamiento normal del Spinner.

 

[![Spinner personalizado en Android 1 - www.jarroba.com](https://jarroba.com/wp-content/uploads/2013/05/Spinner-personalizado-en-Android-1-www.jarroba.com_.png)](https://jarroba.com/wp-content/uploads/2013/05/Spinner-personalizado-en-Android-1-www.jarroba.com_.png)

 

Al pulsar sobre el Spinner se desplegará el listado con las posibles elecciones que estarán personalizadas por nosotros.

 

[![Seleccionar una posición en el Spinner personalizado en Android - www.jarroba.com](https://jarroba.com/wp-content/uploads/2013/05/Seleccionar-una-posición-en-el-Spinner-personalizado-en-Android-www.jarroba.com_.png)](https://jarroba.com/wp-content/uploads/2013/05/Seleccionar-una-posición-en-el-Spinner-personalizado-en-Android-www.jarroba.com_.png)

 

Elegiremos uno y se cambiará el anterior por el que hemos elegido.

 

[![Spinner personalizado en Android 3 - www.jarroba.com](https://jarroba.com/wp-content/uploads/2013/05/Spinner-personalizado-en-Android-3-www.jarroba.com_.png)](https://jarroba.com/wp-content/uploads/2013/05/Spinner-personalizado-en-Android-3-www.jarroba.com_.png)

 

Si has leído el GridView personalizado, decir que es idéntica la forma de operar, por lo que solo hay que hacer un par de cambios para que funcione; rápido y sencillo. Por lo que, el adaptador creado por Jarroba funciona de lujo para cualquier listado de elementos personalizados. Aquí también respetaremos los nombres de los ficheros para no confundir, como es normal, eres libre de cambiarlos por otros.

 

Para este ejemplo hemos cambiado **listado.xml** que queda así:

 

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

 

De **MainActivity.java** hay que sustituir ListView por Spinner, en la variable global:

 

```

private Spinner lista;
```

 

Y en la declaración de la variable:

 

```

lista = (Spinner) findViewById(R.id.spinner_conListadoPersonalizado);
```

 

Además, el Spinner tiene un comportamiento diferente a la hora de elegirse algún elemento. Por lo que ya no usaremos "OnItemClickListener", sino "OnItemSelectedListener". La sustituimos entera por:

 

```

lista.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> pariente, View view, int posicion, long id) {
Lista_entrada elegido = (Lista_entrada) pariente.getItemAtPosition(posicion);

CharSequence texto = "Seleccionado: " + elegido.get_textoDebajo();
Toast toast = Toast.makeText(MainActivity.this, texto, Toast.LENGTH_LONG);
toast.show();
}

@Override
public void onNothingSelected(AdapterView<?> pariente) {
}
});
```

 

Ya tenemos funcionando nuestro Spinner personalizado en un abrir y cerrar de ojos.

 

 

## **Solucción a problema con Listados en Android: Si se usan Views que puedan ser pulsadas e****n las fila de la lista****, esta fila no se puede pulsar**

 

Cuando se ponen alguna View como Buttons, RadioButtons, EditText, CheckBox etc que sean pulsables (no lo son de normal por ejemplo TextView, o ImageView), resulta que el “setOnItemClickListener” del ListView deja funcionar, esto es deja de recibir eventos.

 

Para ilustrar esto, imaginemos que queremos que el usuario pueda marcar con CheckBox si los pájaros de nuestro listado comen insectos (tick en insectívoro), semillas (tick granívoro) o ambos (tick tanto en insectívoro como en granívoro). Habrá que poner algunos CheckBox en cada fila para poder realizar las selecciones que deseamos, quedando como se aprecia en la siguiente imagen:

 

[![Hacer ListView con CheckBox en Android - www.jarroba.com](https://jarroba.com/wp-content/uploads/2013/05/Hacer-ListView-con-CheckBox-en-Android-www.jarroba.com_.png)](https://jarroba.com/wp-content/uploads/2013/05/Hacer-ListView-con-CheckBox-en-Android-www.jarroba.com_.png)

 

Al pulsar los CheckBox funcionan perfectamente como queríamos:

 

[![Pulsar en el CheckBox del ListView con CheckBox en Android - www.jarroba.com](https://jarroba.com/wp-content/uploads/2013/05/Pulsar-en-el-CheckBox-del-ListView-con-CheckBox-en-Android-www.jarroba.com_.png)](https://jarroba.com/wp-content/uploads/2013/05/Pulsar-en-el-CheckBox-del-ListView-con-CheckBox-en-Android-www.jarroba.com_.png)

 

Pero no al seleccionar la fila en sí. Con lo que la siguiente imagen no se permitirá (no saldrá ni el Toast, ni se pondrá naranja la fila, ni entrará el código a ejecutar el contenido de “setOnItemClickListener”, no ocurrirá nada):

 

[![Pulsar en la fila del ListView con CheckBox en Android - www.jarroba.com](https://jarroba.com/wp-content/uploads/2013/05/Pulsar-en-la-fila-del-ListView-con-CheckBox-en-Android-www.jarroba.com_.png)](https://jarroba.com/wp-content/uploads/2013/05/Pulsar-en-la-fila-del-ListView-con-CheckBox-en-Android-www.jarroba.com_.png)

 

No se permitiría pulsarse, pero queremos que se permita.

 

Esto se debe a que Android, por defecto, no puede tener dos cosas que puedan ser pulsadas una encima de la otra, y anula el escuchador de onClick de lo que hay por debajo. En este caso, hemos puesto un botón CheckBox en cada fila. Podremos pulsar en el CheckBox, pero no la entrada que hay por debajo, por lo que no se lanzará nunca el “setOnItemClickListener”.  
 Esto no es un error, es una funcionalidad que está así diseñada por Android. Pero se puede modificar. Es más, para ciertos casos será de utilidad.

 

Para que funcione como queremos, le tenemos que decir a Android que los eventos click los controlaremos nosotros. Para dibujar las entradas, a los elementos clicables –a los CheckBox- les ponemos los atributos **android:clickable="false"** y **android:focusable="false"**. Tendremos el fichero **entradas.xml** como sigue:

 

```

<?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="horizontal" >

<ImageView

android:id="@+id/imageView_imagen"

android:layout_width="80dp"

android:layout_height="80dp"

android:adjustViewBounds="true"

android:scaleType="fitXY"

android:contentDescription="Descripción del contenido de la imagen"

android:src="@android:drawable/ic_menu_gallery" />

<LinearLayout

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:orientation="vertical">

<CheckBox

android:id="@+id/checkBox1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Insectívoro"

android:clickable="false"

android:focusable="false"/>

<CheckBox

android:id="@+id/checkBox2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Granívoro"

android:clickable="false"

android:focusable="false"/>

</LinearLayout>

<LinearLayout

android:layout_width="fill_parent"

android:layout_height="match_parent"

android:gravity="center"

android:orientation="vertical" >

<TextView

android:id="@+id/textView_superior"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Large Text"

android:textAppearance="?android:attr/textAppearanceLarge" />

<TextView

android:id="@+id/textView_inferior"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Small Text"

android:textAppearance="?android:attr/textAppearanceSmall" />

</LinearLayout>

</LinearLayout>
```

 

Luego, en **MainActivity.java**, podemos llamar a los OnClick dentro del onEntrada para diferenciar unas pulsaciones de otras de los CheckBox:

 

```

lista.setAdapter(new Lista_adaptador(this, R.layout.entrada, datos){

@Override

public void onEntrada(final Object entrada, View view) {

if (entrada != null) {

TextView texto_superior_entrada = (TextView) view.findViewById(R.id.textView_superior);

texto_superior_entrada.setText(((Lista_entrada) entrada).get_textoEncima());

TextView texto_inferior_entrada = (TextView) view.findViewById(R.id.textView_inferior);

texto_inferior_entrada.setText(((Lista_entrada) entrada).get_textoDebajo());

ImageView imagen_entrada = (ImageView) view.findViewById(R.id.imageView_imagen);

imagen_entrada.setImageResource(((Lista_entrada) entrada).get_idImagen());

CheckBox checkA = (CheckBox) view.findViewById(R.id.checkBox1);

CheckBox checkB = (CheckBox) view.findViewById(R.id.checkBox2);

checkA.setOnClickListener( new OnClickListener() {

public void onClick(View v) {

CheckBox check = (CheckBox) v ;

Toast toast = Toast.makeText(MainActivity.this, ((Lista_entrada) entrada).get_textoEncima()+ " - Pulsado Insectívoro:"+ check.isChecked(), Toast.LENGTH_LONG);

toast.show();

}

});

checkB.setOnClickListener( new OnClickListener() {

public void onClick(View v) {

CheckBox check = (CheckBox) v ;

Toast toast = Toast.makeText(MainActivity.this, ((Lista_entrada) entrada).get_textoEncima()+ " - Pulsado Granívoro:"+ check.isChecked(), Toast.LENGTH_LONG);

toast.show();

}

});

}

}

});
```

 

Y ya funcionaría como queríamos que funcione.

 

 

## **Comunicar las Views de una fila con las Views de otras**

 

Parecido al anterior. Esta vez queremos votar uno y solo a uno pájaro. Para ello usaremos un RadioButton por entrada, pero como no podemos usar el RadioGroup, lo simularemos nosotros.

 

Queremos poder seleccionar la entrada en sí.

 

[![Pulsar en la fila del ListView con RadioButton en Android - www.jarroba.com.png](https://jarroba.com/wp-content/uploads/2013/05/Pulsar-en-la-fila-del-ListView-con-RadioButton-en-Android-www.jarroba.com_.png.png)](https://jarroba.com/wp-content/uploads/2013/05/Pulsar-en-la-fila-del-ListView-con-RadioButton-en-Android-www.jarroba.com_.png.png)

 

Y también votar. Para esto necesitamos que cuando seleccionemos el RadioButton de un pájaro se quite la selección de otro que hubiera previamente seleccionado. Esto es así, porque solo queremos que se pueda seleccionar un RadioButton de todos los del listado, por lo que habrá que saber cuál se seleccionó anteriormente para quitarlo.

 

[![Pulsar en el RadioButton del ListView con RadioButton en Android - www.jarroba.com](https://jarroba.com/wp-content/uploads/2013/05/Pulsar-en-el-RadioButton-del-ListView-con-RadioButton-en-Android-www.jarroba.com_.png)](https://jarroba.com/wp-content/uploads/2013/05/Pulsar-en-el-RadioButton-del-ListView-con-RadioButton-en-Android-www.jarroba.com_.png)

 

Para este ejemplo estamos usando el siguiente **entradas.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"

android:orientation="horizontal" >

<ImageView

android:id="@+id/imageView_imagen"

android:layout_width="80dp"

android:layout_height="80dp"

android:adjustViewBounds="true"

android:scaleType="fitXY"

android:contentDescription="Descripción del contenido de la imagen"

android:src="@android:drawable/ic_menu_gallery" />

<LinearLayout

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:gravity="center"

android:orientation="vertical" >

<RadioButton

android:id="@+id/radioButton_votar"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:clickable="false"

android:focusable="false"

android:text="Votar" />

</LinearLayout>

<LinearLayout

android:layout_width="fill_parent"

android:layout_height="match_parent"

android:gravity="center"

android:orientation="vertical" >

<TextView

android:id="@+id/textView_superior"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Large Text"

android:textAppearance="?android:attr/textAppearanceLarge" />

<TextView

android:id="@+id/textView_inferior"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="Small Text"

android:textAppearance="?android:attr/textAppearanceSmall" />

</LinearLayout>

</LinearLayout>
```

 

Y para simular el RadioGroup, en **MainActivity.java**, declaramos como global:

 

```

private RadioButton radioButton_pulsado;
```

 

Y el código que lo simula es:

 

```

lista.setAdapter(new Lista_adaptador(this, R.layout.entrada, datos){

@Override

public void onEntrada(final Object entrada, View view) {

if (entrada != null) {

TextView texto_superior_entrada = (TextView) view.findViewById(R.id.textView_superior);

texto_superior_entrada.setText(((Lista_entrada) entrada).get_textoEncima());

TextView texto_inferior_entrada = (TextView) view.findViewById(R.id.textView_inferior);

texto_inferior_entrada.setText(((Lista_entrada) entrada).get_textoDebajo());

ImageView imagen_entrada = (ImageView) view.findViewById(R.id.imageView_imagen);

imagen_entrada.setImageResource(((Lista_entrada) entrada).get_idImagen());

RadioButton voto = (RadioButton) view.findViewById(R.id.radioButton_votar);

voto.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

if (radioButton_pulsado!=null)

radioButton_pulsado.setChecked(false);

radioButton_pulsado = (RadioButton) v;

Toast toast = Toast.makeText(MainActivity.this, ((Lista_entrada) entrada).get_textoEncima()+ " VOTADO", Toast.LENGTH_LONG);

toast.show();

}

});

}

}

});
```
