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/ . Notar que en este artículo emplearemos como base el ejemplo de listado descrito en detalle en el anterior artículo. 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:
Además, nos interesa que puedan pulsar las teselas, para poder controlar lo que ocurra con ellas.
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 listado.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
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.
Al pulsar sobre el Spinner se desplegará el listado con las posibles elecciones que estarán personalizadas por nosotros.
Elegiremos uno y se cambiará el anterior por el que hemos elegido.
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 en 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:
Al pulsar los CheckBox funcionan perfectamente como queríamos:
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):
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í.
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.
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(); } }); } } });
Hola,
Tengo una duda, estoy intentando hace un ListView de modo que muestres varios radio button (Cada apartado del listiview será un TextView, un RadioGrupo y cuatro RadioButton), pero al bajar la vista, y marcar, marca aleatoriamente, los de arriba o los de abajo:
public abstract class AdaptadorRespuestas extends BaseAdapter {
private ArrayList respuestas;
private Context context;
private int R_layout_idView;
private RadioButton selected = null;
public AdaptadorRespuestas(ArrayList respuestas, Context context, int r_layout_idView) {
super();
this.respuestas = respuestas;
this.context = context;
this.R_layout_idView = r_layout_idView;
}
@Override
public int getCount() {
return respuestas.size();
}
@Override
public Object getItem(int position) {
return respuestas.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if(convertView == null){
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.inflate(R_layout_idView, null);
holder = new ViewHolder();
holder.pregunta = (TextView) convertView.findViewById(R.id.textViewPreguntaDetalle);
holder.respuesta1 = (RadioButton) convertView.findViewById(R.id.radioButton);
holder.respuesta2 = (RadioButton) convertView.findViewById(R.id.radioButton2);
holder.respuesta3 = (RadioButton) convertView.findViewById(R.id.radioButton3);
holder.radioGroup = (RadioGroup) convertView.findViewById(R.id.radioGrupo);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
onEntrada(respuestas.get(position), convertView);
return convertView;
}
public abstract void onEntrada(Object respuesta, View view);
public static class ViewHolder{
private TextView pregunta;
private RadioButton respuesta1, respuesta2, respuesta3 ;
private RadioGroup radioGroup;
}
}
Puedes probar a guardar el radiobutton pulsado en una variable global.
Hola Ramón, una duda, como logro insertar un EditText o Spinner dentro del ListView?, al dezplazarlo (scrolling), los elementos que se pierden de la vista se resetean los spinner y edittex ya ingresados.
En el adaptador tienes que implementar el guardado de los datos y el rellenado desde de los datos, pues al hacer scroll y ocultarse los elementos de la pantalla los datos se pierden. También tienes la opción de usar recyclerView https://developer.android.com/guide/topics/ui/layout/recyclerview?hl=es-419
Hola Ramon.
Te saludo desde Colombia, y quiero felicitarte por tus excelentes publicaciones. Necesito preguntarte sobre lo siguiente:
Tego un listado con un Radiobbuton, un par te TexViews , y (tres TextViews, los cuales estan Ocultos son un detalle de la la informacion de esa fila), adicionales, mi problema consiste en que necesito al seleccionar una fila, en ese momento se marca el radiobuton y se le da visibilidad a los tres TexViewsviews que estaban ocultos, al presionar nuevamente otra fila debe suceder los mismo pero adicionalmente debo desmarcar el Radiobbuton selecconado anteriormente y ocultar los tres TexViews que habian aparecido en esa fila.,
Con tu ayuda logre marcar el RadioButton pero no he logrado ocultar y mostrar los tres texViews de la fila seleccionada ya que se activan en diferentes filas.
Te agradezco mucho tu valiosa ayuda .
Puedes guardar la variable de algún modo (global, SharedPreferences, Singleton, etc) y cuando pulsen desmarcar lo que necesites con:
radioButton_pulsado.setChecked(false);
Hola, Ramón.
Me gustaría saber cómo hacer un spinner de listas (que cada elemento sea una lista que al pulsarlo me vuelque el resultado en un contenedor).
Si es muy complicado, también me vale hacer varias listas independientes, cada una en su fragment, y poder llamarlas desde el mismo proyecto, a ser posible desde el mismo contenedor.
Gracias.
Puedes hacer un Spinner con listas, tienes un ejemplo completo en http://jarroba.com/expansion-listview/ 😉
como hago para traer las imagenes de internet con este ejemplo
GridView personalizado en Android en vez de una ListView
Primero tendrías que descargar las imágenes (Más información sobre como conectar a Internet en http://developer.android.com/intl/es/training/basics/network-ops/connecting.html), una vez que las tengas en el dispositivo las puedes colocar en un ImageView con la clase Drawable.
Saludos Maestro, quiero saber, en caso del Spinner Personalizado, si quiero que en el Spinner se me muestre una imagen y un texto al lado, como en el ejemplo, pero que al seleccionar un Item, este se me agregue a un ListView, cómo podría hacerlo???
Te agradecería un montón si me contestas.
Gracais de antemano, y feliz día.
Hola Oscar. Lo que necesitas es pasar o bien el Bitmap al listado o mejor el id si la tienes en la carpeta res o descargada. Luego solo te queda añadirla al Adapter, referenciar las View y refrescar Adapter con notifyDataSetChanged().
Hola,
Hay que prgramar con eclipse???? o podemos utilizar android studio gracias.
Hola. Ahora mismo recomiendo trabajar con Android Studio, pues Eclipse dejará de tener soporte.
De momento no hemos tenido tiempo para actualizar algunos artículos a Android Studio, pero el código y la explicación sirve igualmente se trabaje con Eclipse o con Android Studio 😉
Seguí toda la secuencia con éxito. Muy agradecido por sus enseñanzas.
Gracias por lo didáctico y útil de esta página. Felicitaciones profe. Vengo siguiendo estos prácticos ejemplos y tengo un problema en el GridView. No logró arrancar en el emulador porque me aparece este siguiente mensaje seguido de un largo detalle:
FATAL EXCEPTION: main
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
No hice mas que modificar el ListView anterior que si salio perfecto. Por avor una ayuda. Estoy con Android Studio.
Aunque arranca en el dispositivo físico Alcatel 4010, pero es preocupante lo del emulador.Por favor ayuda.
Hola Miguel,
Si has puesto imágenes de gran tamaño has de hacer una gestión eficiente para evitar fugas de memoria (Más información en: http://android-developers.blogspot.de/2009/01/avoiding-memory-leaks.html). Te recomiendo que sigas los siguientes pasos para una correcta gestión de memoria con las imágenes: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
hola buenas tardes este tutorial me sirvio muy bien me gustaria saber como le puedo hacer para abrir la informacion en un activity si me pudieras ayudar te lo agradeceria
Hola David. Simplemente combínalo con el artículo de Activity de http://jarroba.com/activity-entender-y-usar-una-actividad/, en el momento en el que se pulsa. También tienes ejemplos en nuestro libro gratuito de Android en http://jarroba.com/libro-android-100-gratis/
HoOla, tengo la misma duda de David, sin embargo no me carga la pàgina de tu libro, serà que me puedas ayudar?
Gracias, tu aporte es genial :3
Prueba con un navegador como Chrome o Firefox, también pudiera ser necesario que tengas que actualizar el navegador. También puedes descargar el libro directamente con los Linqs facilitados 🙂
Buenas…
Tengo un ListView con un adaptador pero lo que no sé hacer es que no se muestren todos los elementos, sino solamente los que sean de un tipo concreto que me lo da un método que uso en una clase, pero no sé donde debo hacer la restricción, ¿quizás en el método getview() del adapter? ¿cómo?
Muchas gracias
Hola Miriam,
Es mejor que hagas el filtrado de datos en la base de datos (o en el método que te los da; sino puedes en el método que te da los datos, en el ArrayList o la estructura de datos que te devuelva). Es decir, pásale solo el ArrayList al Adapter con los datos que quieras mostrar únicamente.
1-yo tengo un listview y quisiera colocarle un CheckBox.
2- como puedo arreglar un listview para que se muestre ordenadamente.
ejemplo:
nombre: apellido:
edad: lugar:
y asi sucesivamente… que muestre el listview ordenadamente segun mi requerimiento para mostrarlo.
espero me puedan ayudar.
Hola Jorge,
en esta entrada te mostramos como poner CheckBox a las filas de un listado. Para el orden, se lanza la consulta de orden a la base de datos (ORDER BY) y ya solo es mostrar el cursor en el listado 🙂
Hola que tal?, primero de todo felicitaros por el blog, y por los tutoriales, que están muy bien.
Pero al realizar este tutorial me gustaría ir un poco mas alla, pero no he conseguido hacerlo, os comento, en mi aplicación en lugar del checkbutton, tengo un ImageButton, y me gustaría que al pulsarlo, se cambiara el texto de ese elemento del textview, lo hago así:
ib.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
ib = (ImageButton) v;
String actual=txt.getText().toString();
if (actual.equals(«hola»))
txt.setText(((Lista_entrada) entrada).get_txt());
else
txt.setText(«hola»);
}
});
El problema esta en que se modifica el texto pero solo en el ultimo elemento del ListView que se ha mostrado por pantalla y no en el elemento del ListView que se ha pulsado.
Gracias por la atención! un saludo y seguid asi!
Hola Javier,
ese es un problema de Views. Te está encontrando otra que no es la pulsada. Echa un vistazo a estos ejemplos, donde tratamos pulsaciones en cada fila del listado para hacer cosas diferentes en cada fila: http://jarroba.com/expansion-listview/
Si lo he hecho siguiendo el ejemplo de los checkbox, el ib.setOnClickListener(new View.OnClickListener() esta dentro del Onentrada y dentro del if, he probado haciendo como con el boton, txt = (TextView) v; pero provoca el cierre de la aplicacion.
¿El OnClick() lo tienes dentro del OnEntrada()? Si no está dentro no podrás llamar a las Views, ya que no podrás obtener el objeto view.
Claro, esta todo dentro del onEntrada, tal que asi:
lista = (ListView) findViewById(R.id.ListView_listado);
lista.setAdapter(new Lista_adaptador(this, R.layout.entrada, datos){
@Override
public void onEntrada(final Object entrada, View view) {
if (entrada != null) {
TV1 = (TextView) view.findViewById(R.id.TV_1);
TV1.setText(((Lista_entrada) entrada).gettv1());
TV2 = (TextView) view.findViewById(R.id.TV_2);
TV2.setText(((Lista_entrada) entrada).gettv2());
txt = (TextView) view.findViewById(R.id.TV_3);
txt.setText(«hola»);
ib =(ImageButton)view.findViewById(R.id.show);
ib.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
ib = (ImageButton) v;
String actual=txt.getText().toString();
if (actual.equals(“hola”))
txt.setText(«adios»);
else
txt.setText(“hola”);
}
});
}
}
});
Quiero que cada vez que pulso el botón se cambie el texto del TextView que hay en esa entrada del ListView, pero cambia el de la ultima entrada del ListView que se ha mostrado por pantalla.
Parece que te está tomando la última referencia de la View dibujada, no debiera ya que se debería de guardar la referencia. Ponla como final en el parámetro que le entra a onEntrada, en «view», al igual que tienes «entrada». También prueba a implementar el patrón ViewHolder, que es lo siguiente que hay que hacer; tienes un ejemplo en: http://developer.android.com/training/improving-layouts/smooth-scrolling.html
Buenas… muy buen tutorial, pero mis dudas resultan de tener 2 spinner comunicados, es decir, el tipico ciudad y provincia, pues pulsando en el segundo quisiera que se me añadiera a un listview, consigo sacar la información en un toast, y todo el segundo spinner en el listview, pero solo el elemento seleccionado no.
Gracias.
Hola Mar,
si no te entiendo mal ¿necesitas seleccionar un elemento en un Spinner y que cargue luego otro? Puedes hacerlo al detectar la selección del primer spinner.
Hola,
Saludos desde Colombia.
Y muchas gracias por su blog, me ha sido de gran utilidad.
Quería saber si me podrían dar alguna sugerencia para un problema que tengo con un ImageButton.
Bueno, la activity contiene un listview y un spinner.
Según lo que está seleccionado en el spinner se llenará el listview.
Dentro del listview tengo un TextView y un ImageButton.
Al presionar el ImageButton este debe cambiar de imagen, bueno
le he asignado el evento, pues, sí cambia de imagen, pero al hacer scroll en el listview
regresa a la imagen que tenía antes, bueno, quería saber alguna sugerencia
para resolver ese pequeño inconveniente.
Hola Luís,
el problema que describes es por el refresco que hace Android a los listados para ahorrar memoria. Es decir, toda View que entra en la pantalla, para que el usuario la vea, es creada; por el contrario, toda a View que se salga de la pantalla es destruida. Por lo que siempre has de guardar en memoria (Base de datos por ejemplo, mira las opciones en http://developer.android.com/guide/topics/data/data-storage.html) los cambios de estado y recargarlos al crearse la View (en el caso de este ejemplo http://jarroba.com/listview-o-listado-en-android/ en el OnEntrada() ).
Muchas gracias, lo intentaré, ya había visto otras webs en que se decían cosas similares, pero tengo una pregunta, ¿Cúando es ejecutado el método onEntrada?
El método OnEntrada() se ejecuta cuando se ejecuta el getView() del Adapter (te recomiendo que mires en http://jarroba.com/listview-o-listado-en-android/). No es una ciencia exacta, pues el getView() lo controla el SDK de Android, pero se ejecuta normalmente cuando el usuario ve las Views (las filas del listado)
Buenas que tal, es un ejemplo muy bueno los felicito
Tengo un problema, cree un proyecto exactamente igual al del caso del checkbox, pero sin usar la imagen, pero en el mio ingreso unos 20 elementos en la lista, cuando selecciono uno de los primeros elementos automaticamente uno de los ultimos se selecciona solo y luego al bajar y subir la lista se empiezan a seleccionar elementos aleatoriamente, a que podria deberse? me podrian ayudar? Saludos.
Hola Ervin,
parece apuntar a un problema con las Views. Si estás usando el Adaptador del ejemplo, comprueba el código que está en el OnEntrada().
que tal, bueno tengo todo el MainActivity.java exactamente igual, solo que agrego los 20 elementos de la lista por medio de un ciclo for (obviamente los titulos y las descripciones de cada elemento son diferentes) y nada, sigue con el problema :/
Necesito ver el código para poder echarte una mano. Cópiamelo y le echo un vistazo.
Es exactamente tu código, pero ya se lo que pasa, el problema es que al hacer scroll, los elementos de la parte no visible se marcan de manera automática cuando es marcado uno de la parte visible, esto sucede porque Android reutiliza las mismas vistas una y otra vez a la hora de pintar los elementos en pantalla, Este ejemplo esta muy bien cuando vas a trabajar con pocos elementos, pero a la hora de trabajar con muchos (mas de 15 aprox) es necesario gestionar el uso de los checkbox, es decir, que en la clase Lista_entrada, tengas una variable que determine si el checkbox esta seleccionado o no y la modifiques cada vez que le haga click al chekbox, puedes asociarla mediante el tag del checkbox o de la forma que prefieras 😉
Gracias Ervin por dar solución a un posible problema 🙂
Cuando se trabaja con listas muy grandes todo suele pasar por base de datos para guardar los estados de cada fila y cargarlos cuando Android los solicite al pintar las Views. En Android es muy importante guardar todos los estados y recargarlos cuando le toca en el ciclo de vida.
hola buenas Ramon
muy bueno tu pagina los tutoriales son excelentes.
tengo una consula haber si me podrías ayudar, tengo un ListView que es personalizado y contiene un boton con el cual yo quiero presionar este boton y que me aparesca un activity, pero al momento de poner el codigo no me ocurre un error…
codigo.
——-este codigo esta dentro del set adapter del listview————-
btn_Ver.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
Intent i=new Intent(Cine.this,Plantilla_Pelicula.class);
i.putExtra(«Titulo»,txtTitulo.getText().toString());
i.putExtra(«Sinopsis», txtDescrip.getText().toString());
startActivity(i);
}
});
———————————————————————–
espero tu ayuda…
Gracias.
Hola Alexander,
el código lo veo correcto. Comprueba que la Activity que abres herede de Activity y que está declarada en el AndroidManifest.xml
Sino, pon el error para ver que le pasa.
Hola, quería hacer una consulta respecto a gridview como podria recuperar el valor de un item del gridview. Pude recuperar la posicion del item al hacer click pero no se como recuperar la informacion que tiene la celda. En mi caso es un string. Espero se entienda.
Gracias
Hola Marcos,
tienes un ejemplo de recuperar el valor de un elemento de ListView en http://jarroba.com/listview-o-listado-en-android/ (GridView se hace igual que en ListView)
Hola, me podrias decir si es posible que al darle click a un spinner o a un listview reprodusca instantaneamente una cancion?
¡Sí se puede 🙂 ! Tan solo ejecuta la canción en el evento de escucha, en setOnItemClickListener() del listado.
Hola Ramón,
Antes que nada, felicidades por la web ya que tiene multitud de ejemplo bien explicados.
Me gustaría saber como puedo generar un listview o gridview con togglebutton y, dependiendo de la posición de estos, efectuar una tarea u otra.
La generación del listview o el gridview lo tengo claro pero mi problema reside en identificar el botón pulsado y ejecutar las operaciones necesarias.
Un ejemplo sería escribir un 1 si el botón está pulsado en un mysql o un 0 si no lo está.
Muchas gracias por tu atención.
Un saludo.
Buenas Jose,
gracias por las felicitaciones 🙂
En relación a tu consulta, en esta misma página tienes como diferenciar unas Views (es decir, identificar el botón pulsado) de otras dentro del listado, echa un vistazo al apartado «SOLUCCIÓN A PROBLEMA CON LISTADOS EN ANDROID: SI SE USAN VIEWS QUE PUEDAN SER PULSADAS EN LAS FILA DE LA LISTA, ESTA FILA NO SE PUEDE PULSAR». Ya diferenciado el botón puedes hacer lo que necesites, como guardar el resultado en una base de datos.
Hola Ramón.
Con este método que haces para rellenar los listView veo que no utilizas un Holder, con lo que entiendo que cada vez que se crea la vista utilizas el findViewById con la sobrecarga de tiempo y uso de memoria que eso significa. No sé si lo que te comento es realmente así. De otra forma me parece interesante como planteas el Adapter, pero me gustaría saber sí estoy confundida y puedo utilizar sin problema este Adapter tal y como lo planteas tu
Encantado Teresa,
no te equivocas para nada, muy bien visto: utilizar el patrón View Holder agiliza la carga del listado al liberar recursos del hilo de la interfaz gráfica.
El tutorial del listado está indicado para iniciarse con ListView y para implementarlo rápidamente sin problemas. Cree un Adapter sencillo que fuera muy intuitivo de implementar y de entender. De ahí se puede tomar el código y modificarlo para adaptarlo al listado de cada uno. De todas maneras, para el tema de listados, y aunque todo cuenta a la hora de optimizar, hay que preocuparse más por el cacheado si hay imágenes o muchos datos, y que la fuente de datos que rellena el listado funcione en un hilo en segundo plano, es fundamental.
Sus tutoriales son de gran ayuda.
Tengo un duda y quisiera poder contar con su apoyo.
Estoy realizando una app, por medio de la cual en un layout que contiene un spinner, selecciono un item (ej. un Estado) para luego al pulsar un boton pasar a otro layout y mostrar información en un ExpandableListView. El problema que estoy teniendo es para rellenar ese ExpandableListView dependiendo la selección que se realice en el layout que contiene el spinner.
He pensado en un solución pero no se como implementarla…..
Cuando selecciono un item en el spinner del layout Selección.xml y oprimo el boton, logro pasar la posición del item seleccionado (correspondiente a un Estado) al siguiente layout Lista.xml, siendo el caso que dependiendo de la posición del item selección deseo rellenar información a un expandablelistview por medio de un Switch Case…..
Muchas Gracias de antemano por su respuesta….
Muy buenas Engel,
lo que comentas se podría realizar que al pulsar en el Spinner se elija un conjunto de datos (un array, una consulta en la base de datos, etc), que se deban de cargar en el ListView. Si quieres hacer un ExpandableListView, que es un tipo especial de listas, tendrás que hacer un Adapter que herede de BaseExpandableListAdapter o usando un SimpleExpandableListAdapter; y pasarle en el adaptador los datos.
Buenas Ramón,
Me podrías mandar el proyecto: COMUNICAR LAS VIEWS DE UNA FILA CON LAS VIEWS DE OTRAS, lo he intentado de mil maneras pero aun no consigo con la solución porfa. Estoy haciendo una aplicación con php JSON y android se trata de una Test Online via Movil, y tu aplicación se presta para el caso. espero tu respuesta. Gracias.
PD: Esta chevere tu blog. Felicitaciones.
Muy buenas Luís,
vamos a subir los proyectos al Github para que os los podáis descargar todos 🙂
Hola que tal estos ejemplos que explicas serian igual para llenar un spinner, ya que intento hacer uno pero con una base de datos donde me traigo : foto, nombre y valor, saber si cambian algunas cosas o totalmente el adaptador y lo demas o solo en la codificacion al momento de asignar el espinner al adaptador, tambien saber si tienes un ejemplo para póderme guiar, saludos.
Buenas juan,
Efectivamente, si queremos hacer un Spinner personalizado, también podemos. Hemos actualizado el artículo con un ejemplo completo que solventará tu duda. Esperamos que te sirva 🙂