android - verificacion - Actualizar el estado de la casilla de verificación en una lista
marcar casilla html (2)
No estoy seguro de haber seguido todo lo que dijo allí, pero tenga en cuenta que ListView
recicla las vistas a medida que se desplaza. Esto significa que no puede suponer que una vista estará en un estado predeterminado al inicio de getView
. Esta es probablemente la razón por la que no funciona cuando deja de restablecer la casilla de verificación al estado correcto cada vez que obtiene una nueva vista.
Dicho esto, ¿consideraste utilizar la herramienta de casilla de verificación de ListView
? Establezca su modo de elección en CHOICE_MODE_MULTIPLE y use uno de los diseños proporcionados, como android.R.layout.simple_list_item_multiple_choice
.
Tengo una vista de lista con un diseño de fila personalizado (list_row.xml) que contiene el elemento CheckBox:
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:orientation="horizontal"
android:weightSum="1.0">
<TableRow>
<TextView android:id="@+id/name"
android:layout_weight=".85"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:text="sample"
android:textSize="24sp">
</TextView>
<CheckBox android:id="@+id/enabled"
android:layout_weight=".15"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:focusable="false">
</CheckBox>
</TableRow>
</TableLayout>
En mi lista de actividades, tengo ListRowAdapter:
private static class ListRowAdapter extends ArrayAdapter<ListRow> implements
CompoundButton.OnCheckedChangeListener {
private List<ListRow> items;
private LayoutInflater vi;
private SparseBooleanArray mCheckStates;
public ListRowAdapter(Context context, int textViewResourceId,
List<ListRow> objects) {
super(context, textViewResourceId, objects);
this.items = objects;
this.vi = LayoutInflater.from(context);
this.mCheckStates = new SparseBooleanArray(objects.size());
for(int i=0;i<mCheckStates.size();i++){
mCheckStates.put(i,items.get(i).isEnabled());
}
Log.i("VIEW", "constructor");
}
public boolean isChecked(int position) {
return mCheckStates.get(position, false);
}
public void setChecked(int position, boolean isChecked) {
mCheckStates.put(position, isChecked);
items.get(position).setEnabled(isChecked);
notifyDataSetChanged();
}
public void toggle(int position) {
setChecked(position, !isChecked(position));
}
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
ListRow r = (ListRow) buttonView.getTag();
r.setEnabled(isChecked);
mCheckStates.put(items.indexOf(r), isChecked);
Toast.makeText(getContext(), "row " + r.getName() + " changed to "+isChecked, Toast.LENGTH_SHORT).show();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
Log.i("VIEW", "init holder");
convertView = vi.inflate(R.layout.list_row, null);
holder = new ViewHolder();
holder.name = (TextView) convertView.findViewById(R.id.name);
holder.enabled = (CheckBox) convertView
.findViewById(R.id.enabled);
convertView.setTag(holder);
} else {
Log.i("VIEW", "using holder");
holder = (ViewHolder) convertView.getTag();
}
ListRow row = items.get(position);
if (row != null) {
holder.name.setText(row.getName());
holder.enabled.setTag(row);
holder.enabled.setChecked(mCheckStates.get(position, false)); holder.enabled.setOnCheckedChangeListener(this);
}
return convertView;
}
static class ViewHolder {
TextView name;
CheckBox enabled;
}
}
En mi actividad (que extiende ListActivity) hago lo siguiente:
private static List<ListRow> rows;
private ListRowAdapter lra;
... y entonces
getListView().setItemsCanFocus(false);
getListView().setTextFilterEnabled(true);
rows = initRows();
lra = new ListRowAdapter(this, R.layout.list_row, rows);
setListAdapter(lra);
y eso funciona bien mientras se desplaza. ¡Pero si no uso la matriz mCheckStates
, falla! Simplemente no puedo entender por qué. ¡Tengo items array como miembro de mi clase Activity y contiene todos los estados de checkboxes! Lo actualizo en el método onCheckedChanged()
como actualizo mCheckState
. Entonces el siguiente código tiene que funcionar:
public boolean isChecked(int position) {
return items.get(position).isEnebled();
}
public void setChecked(int position, boolean isChecked) {
items.get(position).setEnabled(isChecked);
notifyDataSetChanged();
}
public void toggle(int position) {
setChecked(position, !isChecked(position));
}
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
ListRow r = (ListRow) buttonView.getTag();
r.setEnabled(isChecked);
Toast.makeText(getContext(), "row " + r.getName() + " changed to "+isChecked, Toast.LENGTH_SHORT).show();
}
y en el método getView()
:
holder.enabled.setTag(row);holder.enabled.setChecked(row.isEnabled());
Pero no es así Pierde estados de casilla de verificación mientras se desplaza y no sé por qué.
Lo que encontré es que debido a que getView está redibujando y reciclando el elemento de la lista en scroll uno necesita indicar explícitamente cuándo debe marcarse la casilla y cuándo no (solución similar para el color de fondo del elemento seleccionado) en una sentencia como
if (condition) {... set check check code ...} else {... set check casilla desmarcado código ...}
El estado de la casilla de verificación puede derivarse de una matriz que debe actualizarse cada vez que el usuario marca o desmarca la casilla en la vista de lista.