2010-10-24 9 views
8

Ho creato un ListView personalizzato estendendo SimpleCursorAdapter. Il risultato è IMAGE + CheckedTextView (Text + Checkbox).Android Fare clic sulla listaI controlli di verifica errati

Quando faccio un clic lungo su un elemento, tutto funziona correttamente: ottengo l'ID corretto e i dettagli dell'elemento selezionato.

Il problema si verifica quando si tenta di contrassegnare un elemento come selezionato ma si verifica la casella di controllo errata.

Ad esempio: Ho 9 elementi sulla mia lista, ordinati 1-9. se faccio clic su listItem 1, la casella di controllo sulla riga 9 viene controllata. se faccio clic sull'elemento 4, la casella di controllo sulla linea 6 viene controllata e se faccio clic sulla linea centrale, viene controllata.

Chiaramente mi manca qualcosa qui :) Ricordare quando faccio un lungo clic sulla riga (menu contestuale apre), tutto funziona alla grande.

Questa è l'ascoltatore:

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); 
       } 

      } 
     }); 

Apprezzo tutto l'aiuto!

Fammi sapere Se hai bisogno di me per pubblicare più codice.

Grazie!

btw, se clicco su più di uno ... la festa continua ... nessun ordine ovvio ...

EDIT: il codice adattatore

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); 
    } 
} 
+0

Mostraci il tuo adattatore – Falmarri

+0

domanda modificata. Grazie. –

+0

stai registrando il valore di posizione nel listener? Hai altri ascoltatori? – Jim

risposta

11

Mayra è giusto - il problema ha a che fare con il modo in cui ListView sta riutilizzando le tue visualizzazioni. Non è come se ci fossero 9 istanze dell'oggetto CheckedTextView, una per visualizzazione. Invece, ce n'è uno singolo che viene riutilizzato in tutte le righe. Pertanto non è possibile fare affidamento sull'oggetto CheckedTextView per mantenere lo stato della verifica di un elemento. Avrete bisogno di qualche struttura dati aggiuntivi per tenere se una determinata riga è selezionata, per esempio,

ArrayList<Boolean> checkedStates = new ArrayList<Boolean>(); 

Laddove l'elemento ith è vero se e solo se la riga ith dovrebbe essere controllato. Poi all'interno del vostro 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 
     } 
    }); 

Poi all'interno del codice di vista:

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); 
} 

Questo dovrebbe risolvere il problema. Un approccio alternativo sarebbe quello di spostare la logica del fatto che la riga sia controllata o meno nell'oggetto dominio rappresentato dalla riga. Questa sarebbe la mia preferenza.

+0

Grazie per la risposta! Ho provato il tuo suggerimento e non importa cosa ho fatto, ho ottenuto una chiusura forzata per "IndexOutOfBoundsExeption". Qualche idea? –

+0

A un certo punto è necessario aggiungere le voci iniziali a ArrayList. Quando sai quanti elementi ci sono, ad esempio, 'for (int i = 0; i I82Much

+0

Ok grazie mille. proveremo questo! –