Está en la página 1de 11

package com.dagova.ejemplo; import import import import import import import import import import import import java.util.

ArrayList; android.content.Context; android.view.InflateException; android.view.LayoutInflater; android.view.View; android.view.ViewGroup; android.widget.BaseAdapter; android.widget.CompoundButton; android.widget.TextView; android.widget.Toast; android.widget.ToggleButton; android.widget.CompoundButton.OnCheckedChangeListener;

public class DeviceAdapter extends BaseAdapter { private ArrayList<String> lista; private LayoutInflater inflater; public DeviceAdapter(ArrayList<String> lista) { this.lista = lista; // MyContext.context es el contexto de la aplicacion, que yo lo almaceno como atributo estatico de una clase para poder acceder desde cualquier clase de la aplicacion inflater =(LayoutInflater)MyContext.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public int getCount() { return lista.size(); } @Override public Object getItem(int position) { return lista.get(position); } @Override public long getItemId(int position) { // TODO Auto-generated method stub return 0; } // Esto es lo importante, el metodo que devuelve los elementos para que el s.o. los muestre en la lista. @Override public View getView(final int position, View convertView, ViewGroup parent) { View output = null; TextView textView; // yo he utilizado toogle button, podeis utilizar lo que querais, checkbox en su lugar ToggleButton toggleButton; try { // se le indica el xml que contiene la vista a devolver. output = inflater.inflate(R.layout.example, null); }

catch(InflateException ex) { // lo que querais hacer en este caso,mostrar un toast o lo que sea } // obtengo el textview de la fila a devolver, para cambiar su texto textView = (TextView) output.findViewById(R.id.TextView); // pongo el texto del elemento textView.setText(lista.get(position).getName()); // obtengo el toggle button de la vista a devolver toggleButton = (ToggleButton) output.findViewById(R.id.ToggleButton); // especifico que hacer cuando en el se produce un evento toggleButton.setOnCheckedChangeListener ( new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { // lo que hagais aqui es cosa vuestra } } ); return output; } }

El xml que yo he usado es el siguiente:


Cdigo : <?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:gravity="center"> </TextView> <ToggleButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center"> </ToggleButton> </LinearLayout>

Espero que os sirva, un saludo!

Bueno yo tengo una duda nadamas, como puedo hacer que el elemento de la lista sea "clickeable" con todo y que tenga un checkbox, por que cuando le agrego el checkbox ya no puedo hacer click mas que en el checkbox, el elemento de la lista ya no funciona, de que manera arreglo eso?

Lo que devuelves es un objeto de tipo view, llamado output en este caso. Para hacerlo clickeable, basta con que tras el inflate del try escribas output.setOnClickListener... y lo defina

try { // se le indica el xml que contiene la vista a devolver. output = inflater.inflate(R.layout.example, null); output.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method } }); }catch(InflateException ex) { // lo que querais hacer en este caso,mostrar un toast o lo que sea }

Hace una semana comentbamos el modo de crear un ListView para Android con, como mnimo, un CheckBoxen cada fila de la lista. Este mini tutorial de hoy, en el que vamos a explicar como marcar de una todos losCheckBox de un ListView, vamos a basarnos en el contenido explicado en dicho artculo. En principio la metodologa parece sencilla, en nuestro fichero main.xml, adems de declarar un ListView, declaramos en la parte inferior un CheckBox cuyo comportamiento determinaremos ms adelante, de manera que el contenido del main.xml quedara de la siguiente manera:

main.xml
1 2 3 4 5 6 7
<?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"> <ListView android:id="@+id/list"

8 9 10 11 12 13 14 15 16 17 18

android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:drawSelectorOnTop="false"/> <CheckBox android:id="@+id/chkSelectAll" android:text="@string/chkSelectAll" android:visibility="visible" android:layout_width="fill_parent" android:layout_height="wrap_content"/> </LinearLayout>

Hasta aqu todo ha sido coser y cantar, de nuevo hemos de definir un fichero con el Layout de cada una de las filas de lo que ser nuestro ListView, en nuestro caso item.xml

1 2 3 4 5 6 7 8 9 10

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

Una vez que tenemos hecho esto nos bastar con definir el comportamiento de la clase principal para que al marchar el chkSelectAll se marquen todos los CheckBox de la lista, para ello en un principio, con poner el array que determina el valor de cada CheckBox a trueo false, en funcin del caso, debera sernos suficiente. Para ello aadiramos en el onCreatelas liguientes lineas:

1 2 3 4 5 6 7 8 9

chkAll = (CheckBox)findViewById(R.id.chkSelectAll); chkAll.setOnCheckedChangeListener(new OnCheckedChangeListener(){ @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { for (int i = 0; i < adapter.getItemsLength(); i++) { adapter.set(i, b); } } });

El problema nos lo encontramos cuando lo que queremos es que adems de marcarlos en el sistema queremos que se visualicen los CheckBox marcados directamente, para ello, lo que podemos hacer (AVISO: es una solucin un poco cutre y simplemente para salir del paso) es reasignar el adaptador, para lo que despus del for podramos aadir las siguientes lineas:

1 2 3

int pos = list.getFirstVisiblePosition(); list.setAdapter(adapter); list.setSelection(pos);

Si ahora compilamos y ejecutamos el cdigo podremos observar como el comportamiento es el deseado.

Android es un gran sistema operativo para mviles que le supone una competencia directa al iOS, y por lo tanto meterse como programador en su mundo puede ser algo muy atractivo. Pero como programadores ms o menos experimentados sabemos que no todo es un paseo, tal y como algunos pretenden plantearlo; siempre surgen problemas que habremos de solucionar. Hoy, vamos a ver como evitar que, al tener un ListViewen el que cada fila contenga un CheckBox, al hacer scroll, los elementos de la parte no visible se marquen al marcar uno de la parte visible de manera automtica.

Por qu?
Esto sucede porque Android reutiliza las mismas vistas una y otra vez a la hora de pintar los elementos en pantalla, de manera que aunque el CheckBox que ha de mostrar no est seleccionado, se mostrar como tal dado que uno visible anteriormente ya lo estaba. De este modo se ahorra una gran cantidad de ciclos de CPU a la hora de generar la imagen que se va a mostrar. Cmo podemos ver, el comportamiento por defecto del sistema operativo no siempre nos viene bien ya que, en casos como este, puede dar lugar a confusiones en el usuario final de la aplicacin.

Solucin
La manera de solucionar este pequeo inconveniente, aunque no de la forma ms ptima, es tan simple como establecer a mano el valor del CheckBox que ha de mostrarse en cada momento, para ello tendremos que apoyarnos en una serie de clases y ficheros XML. Antes de nada, vamos a analizar los ficheros que componen nuestro Layout, es decir, el que establece la distribucin de la pantalla principal y el que establece el aspecto de cada una de las filas.

main.xml 1 2 3 4

<?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"

5 6 7 8 9 10 11 12

android:layout_height="fill_parent"> <ListView android:id="@+id/list" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:drawSelectorOnTop="false"/> </LinearLayout>

row.xml 1 <?xml version="1.0" encoding="utf-8"?> 2 3


android:layout_height="wrap_content" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

4 5 6 7 8 9 10

android:layout_width="fill_parent"> <CheckBox android:id="@+id/chkItem" android:visibility="visible" android:layout_width="fill_parent" android:layout_height="wrap_content"/> </LinearLayout>

Tal y como se puede observar, hasta este momento no hemos hecho ms que definir dos layouts, uno que contiene un ListView y otro que contiene el CheckBox que ha de aparecer en cada fila. Prosigamos programando nuestra clase Java para manejar estos Layouts:

1 2 3 4 5 6 7 8 9 10 11

package org.dipler.chkList;

import java.util.ArrayList;

import android.app.Activity; import android.content.Context; import android.database.Cursor; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter;

12 13 14 15 16 17 18 19 20 21 22

import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.ListView; import android.widget.CompoundButton.OnCheckedChangeListener;

public class Main extends Activity { private ChkListAdapter adapter; private ListView list; private CheckBox chkAll;

@Override

23 24 25 26 27

public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); list = (ListView)findViewById(R.id.list); fillList(); }

28 29 30 31 32 33 34 35 36 37
private class ChkListAdapter extends BaseAdapter { private void fillList() { int num = 50; adapter = new ChkListAdapter(num); for(int i = 0; i < num; i++){ adapter.addItem(new Item(String.valueOf(i), "item number " + i)); } list.setAdapter(adapter); }

38
private ArrayList<Item> items = new ArrayList<Item>();

39 40 41 42 43 44

private LayoutInflater inflater; private boolean[] itemSelection; public ChkListAdapter(int size) { inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); this.itemSelection = new boolean[size]; }

45 46 47
public void addItem(final Item item) { items.add(item);

48 49 50 51 52 53

notifyDataSetChanged(); }

@Override public int getCount() { return items.size(); }

54 55 56 57 58 59 60 61 62 63 64
@Override @Override public long getItemId(int position) { return position; } @Override public String getItem(int position) { return items.get(position).toString(); }

65 66 67 68 69 70 71 72
public View getView(final int position, View convertView, ViewGroup parent) { convertView = inflater.inflate(R.layout.row, null); final ViewHolder holder = new ViewHolder(); holder.chkItem = (CheckBox)convertView.findViewById(R.id.chkItem); holder.chkItem.setOnCheckedChangeListener(new OnCheckedChangeListener(){ @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

73 74 75 76 77 78

itemSelection[position] = holder.chkItem.isChecked(); } });

holder.chkItem.setChecked(itemSelection[position]); convertView.setTag(holder); holder.chkItem.setText(getItem(position));

79 80 81 82 83 84 85 86 87 88 89 90

return convertView; }

public int getItemsLength() { if(itemSelection == null) return 0; return itemSelection.length; }

public void set(int i, boolean b) { itemSelection[i] = b; }

91 92 93 94 95 96 97
} public static class ViewHolder { public CheckBox chkItem; }

98 99 100 101 102

Como podemos observar el la, bueno, las clases Java que hemos declarado tenemos:

La clase Activity principal que utiliza el Layout main.xml y que en el mtodoonCreate() rellena el ListView con elementos, en nuestro caso de tipo Item (Item es una clase cualquiera con dos atributos, un id y un texto)

El adapter, que es la clase que se va a dedicar a repintar las filas tantas veces como sea necesario llamando al mtodo getView() en cada una de esas ocasiones. La clase ViewHolder que nos facilita el trabajo con la clase Row, esta clase no es en s necesaria, pero vi la idea en amberfog y me gust, de hecho de esta misma pgina obtuve una visin mucho ms clara del funcionamiento de estos artificios llamados Views

El procedimiento para evitar que se marquen solos los CheckBox que cumplen el periodo, es sencillo, llevamos un array de booleanos en el que establecemos el estado de cada elemento de la lista confome cambia el valor del CheckBox, de manera que cada vez quedeseemos mostrar dicho elemento, el mtodo getView(), en lugar de pintar como cree que debera pintar estos CheckBox, los muestra marcados o desmarcados en funcin del array que hemos creado y que vamos actualizando dinmicamente. El mtodo propuesto no es el ms eficiente que nos podamos encontrar, pero funciona y nos puede ayudar a salir del paso.

También podría gustarte