2013-05-03 14 views
6

Ho alcuni problemi con la mia scheda personalizzata ListView (e la sua nuova viewHolder). Ho un ListView con una casella di controllo per ogni elemento (niente di nuovo qui). Il problema è che se ci sono più di 9 elementi nella mia lista, quando controllo la prima casella, il decimo verrà automaticamente controllato (lo stesso vale per il secondo con l'undicesimo) proprio come se ci fosse un ascoltatore per entrambi gli elementi (e io credo che sia il caso in qualche modo).Stato casella di controllo Visualizza spettatore

Ho letto che il problema posizione listView, vista il riciclaggio e il modo ViewHolder per risolverlo qui: How can I make my ArrayAdapter follow the ViewHolder pattern?

Ma probabilmente ho fatto qualcosa di sbagliato, perché non funziona ...

public class PresenceListAdapter extends SimpleAdapter { 
private LayoutInflater inflater; 
private List<Integer> ids; 
private List<String> statuts; 

public PresenceListAdapter (Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to, List<Integer> ids, List<String> statuts) 
{ 
    super (context, data, resource, from, to); 
    inflater = LayoutInflater.from (context); 
    this.ids = ids; 
    this.statuts= statuts; 

} 

@Override 
public Object getItem (int position) 
{ 
    return super.getItem (position); 
} 

@Override 
public View getView (int position, View convertView, ViewGroup parent) 
{ 

    ViewHolder holder; 

    if (convertView == null) 
    { 
     convertView = inflater.inflate (R.layout.list_text_checkbox, null); 

     holder = new ViewHolder(); 

     holder.btn = (Button) convertView.findViewById(R.id.btnRetard); 
     holder.check = (CheckBox) convertView.findViewById(R.id.checkPresent); 

     if (statuts.get(position).equals("P")) { 
      Drawable img = inflater.getContext().getResources().getDrawable(android.R.drawable.presence_online); 
      holder.btn.setCompoundDrawablesWithIntrinsicBounds(img, null, null, null); 
      holder.btn.setEnabled(true); 
      holder.check.setChecked(true); 
     } 
     else if(statuts.get(position).equals("R")) 
     { 
      Drawable img = inflater.getContext().getResources().getDrawable(android.R.drawable.presence_away); 
      holder.btn.setCompoundDrawablesWithIntrinsicBounds(img, null, null, null); 
      holder.btn.setEnabled(true); 
      holder.check.setChecked(true); 
     } 
     else 
     { 
      Drawable img = inflater.getContext().getResources().getDrawable(android.R.drawable.presence_invisible); 
      holder.btn.setCompoundDrawablesWithIntrinsicBounds(img, null, null, null); 
      holder.check.setChecked(false); 
     } 

     convertView.setTag(holder); 
    } 
    else 
    { 
     holder = (ViewHolder) convertView.getTag(); 
    } 

    int id = ids.get(position); 

    if(id != 0) 
    { 
     holder.check.setTag(id); 
     holder.btn.setTag(id); 
    } 

    return super.getView (position, convertView, parent); 
} 

static class ViewHolder { 
    Button btn; 
    CheckBox check; 
} 

E il mio ascoltatore: public void changerPresent (Visualizza v) {

CheckBox checkPresent = (CheckBox) v; 
    int idPersonne = (Integer) checkPresent.getTag(); 
    View parent = (View)v.getParent(); 
    Button btn = (Button) parent.findViewById(R.id.btnRetard); 

    if(checkPresent.isChecked()) { 
     gestion.updatePresence(idPersonne, idSeance, "P"); 

     btn.setEnabled(true); 
     setBtnRetardPresent(btn);   
    } 
    else 
    { 
     gestion.updatePresence(idPersonne, idSeance, "A"); 
     btn.setEnabled(false); 
     setBtnRetardAbsent(btn); 

    } 

} 

gradirei qualsiasi aiuto, a questo punto, io sono lavorando su questo per ore ora.

Grazie mille.

risposta

13

Ecco come ho fatto funzionare:

In primo luogo, è necessario un array separato per il tuo stato controllato. Deve avere le stesse dimensioni del tuo adattatore getCount().

Quindi su getView, setOnCheckedChangedListener del checkbox DEVE PRECEDERE le dichiarazioni checkbox.setChecked.

esempio:

holder.checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() { 
    @Override 
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 
    isChecked[position] = isChecked; 
    } 
}); 

holder.checkBox.setChecked(isChecked[position]); 
+0

Perfetto! Grazie per le tue spiegazioni. – jthel

+0

Interessante, puoi dire perché checkchangelistener deve precedere setChecked? Grazie –

+2

se hai altre cose che vuoi fare su onCheckChanged (come aggiornare il colore dell'elemento dell'elenco, ecc.), Queste cose non succederanno se chiami setChecked prima di impostare il listener. – josephus

0

Il problema è a causa del fatto che listview ricicla essa vede

così in getView() Metodo

 if (convertView == null) 
     { 
    ........ 
     } 
    else 
     { 
      holder = (ViewHolder) convertView.getTag(); 


     } 
    // Uncheck needed boxes here... You need to implement your logic 
     if('position' is checked earlier) 
     holder.check.setChecked(true); 
     else 
     holder.check.setChecked(false); 

È necessario scrivere il codice per gestire lo stato della vista se il convertito non è nullo , perché è una vista già utilizzata che potrebbe avere spuntato le caselle di controllo.

0

È necessario impostare lo stato di fuori CheckedBox l'inizializzazione di ViewHolder, come il seguente codice:

if (convertView == null) { 
    viewHolder = new ViewHolder(); 
    convertView.setTag(viewHolder); 
} else { 
    viewHolder = (ViewHolder) convertView.getTag(); 
} 

viewHolder.checkedBox.setChecked(); 

BTW: utilizzare SparseBooleanArray invece di due dell'elenco per memorizzare lo stato CheckedBox.