Android Clique em ListItem Verifica a caixa de seleção errada
-
25-09-2019 - |
Pergunta
Eu criei um ListView personalizado, estendendo o SimpleCurSorAdapter. O resultado é Image + CheckEdTextView (Texto + Caixa de seleção).
Quando clico por muito tempo em um item, tudo funciona bem - recebo o ID e os detalhes certos do item clicado.
O problema ocorre quando tento marcar um item como verificado, mas ele verifica a caixa de seleção errada.
Por exemplo: Eu tenho 9 itens na minha lista, classificados por 1-9. Se eu clicar no ListItem 1, a caixa de seleção na linha 9 estará sendo verificada. Se eu clicar no item 4, a caixa de seleção na linha 6 estará sendo verificada e, se eu clicar na linha do meio, ele estará sendo verificado.
Claramente estou perdendo alguma coisa aqui :) Lembre -se de quando clico há muito tempo na linha (o contextmenu abre), tudo funciona muito bem.
Este é o ouvinte:
lv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
CheckedTextView markedItem = (CheckedTextView) view.findViewById(R.id.btitle);
if (!markedItem.isChecked()) {
markedItem.setChecked(true);
} else {
markedItem.setChecked(false);
}
}
});
Aprecie qualquer ajuda!
Deixe -me saber se você precisar que eu poste mais código.
Obrigada!
BTW, se eu clicar em mais de um ... a festa continua ... sem ordem óbvia ...
Editar: o código do adaptador
public class ImageCursorAdapter extends SimpleCursorAdapter {
private Cursor c;
private Context context;
private String url;
private TextView bUrl;
public ImageCursorAdapter(Context context, int layout, Cursor c,
String[] from, int[] to) {
super(context, layout, c, from, to);
this.c = c;
this.context = context;
}
public View getView(int pos, View inView, ViewGroup parent) {
View v = inView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.image_list, null);
}
this.c.moveToPosition(pos);
final TextView bTitle = (TextView) v.findViewById(R.id.btitle);
String bookmark = this.c.getString(this.c.getColumnIndex(Browser.BookmarkColumns.TITLE));
byte[] favicon = this.c.getBlob(this.c.getColumnIndex(Browser.BookmarkColumns.FAVICON));
if (favicon != null) {
ImageView iv = (ImageView) v.findViewById(R.id.bimage);
iv.setImageBitmap(BitmapFactory.decodeByteArray(favicon, 0, favicon.length));
}
bTitle.setText(bookmark);
return (v);
}
}
Solução
Mayra está certa - o problema tem a ver com a maneira como a ListView está reutilizando suas opiniões. Não é como se houvesse 9 instâncias do CheckedTextView
objeto, um por visualização. Em vez disso, há um único que é reutilizado em todas as linhas. Portanto, você não pode confiar no objeto CheckEdTextView para manter o estado de se um item é verificado. Você precisará de alguma estrutura de dados adicional para sustentar se uma determinada linha é verificada, por exemplo,
ArrayList<Boolean> checkedStates = new ArrayList<Boolean>();
Onde o ith
elemento é verdadeiro se o ith
A linha deve ser verificada. Então, dentro do seu itemClickListener:
lv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
boolean currentlyChecked = checkedStates.get(position);
checkedStates.set(position, !currentlyChecked);
// Refresh the list
}
});
Então, dentro do seu código de visualização:
public View getView(int pos, View inView, ViewGroup parent) {
View v = inView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.image_list, null);
}
this.c.moveToPosition(pos);
final TextView bTitle = (TextView) v.findViewById(R.id.btitle);
String bookmark = this.c.getString(this.c.getColumnIndex(Browser.BookmarkColumns.TITLE));
byte[] favicon = this.c.getBlob(this.c.getColumnIndex(Browser.BookmarkColumns.FAVICON));
if (favicon != null) {
ImageView iv = (ImageView) v.findViewById(R.id.bimage);
iv.setImageBitmap(BitmapFactory.decodeByteArray(favicon, 0, favicon.length));
}
bTitle.setText(bookmark);
// Change the state of the checkbox to match that of the row's checked state.
// This check box item is reused for every row, so we need to reset its state each
// time the row is rendered.
CheckedTextView markedItem = (CheckedTextView) view.findViewById(R.id.btitle);
markedItem.setChecked(checkedStates.get(pos));
return (v);
}
Isso deve resolver seu problema. Uma abordagem alternativa seria mover a lógica de se a linha é verificada ou não para o objeto de domínio que a linha representa. Essa seria minha preferência.