2012-08-19 6 views
5

Ho un adattatore personalizzato:Android ListView personalizzato ripete selezione sfondo

public class PhraseCustomAdapter extends BaseAdapter 
{ 
public String original[]; 
public String translation[]; 
public String transcription[]; 

public Activity context; 
public LayoutInflater inflater; 

public PhraseCustomAdapter(Activity context,String[] original, String[] translation, String[] transcription) { 
    super(); 

    this.context = context; 
    this.original = original; 
    this.translation = translation; 
    this.transcription = transcription; 

    inflater = LayoutInflater.from(context); 
    this.inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
} 

@Override 
public int getCount() { 
    // TODO Auto-generated method stub 
    return original.length; 
} 

@Override 
public Object getItem(int position) { 
    // TODO Auto-generated method stub 
    return position; 
} 

public String getItemTranlation(int position) { 

    return translation[position]; 
} 

public String getItemTranscription(int position) { 
    // TODO Auto-generated method stub 
    return transcription[position]; 
} 

public String getItemOriginal(int position) { 
    // TODO Auto-generated method stub 
    return original[position]; 
} 


@Override 
public long getItemId(int position) { 
    // TODO Auto-generated method stub 
    return position; 
} 

static class ViewHolder 
{ 
    ImageView imgViewLogo; 
    TextView txtViewOriginal; 
    TextView txtViewTranslation; 
    TextView txtViewTranscription; 
} 

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

    ViewHolder holder; 
    if (convertView == null) { 
     holder = new ViewHolder(); 
     convertView = inflater.inflate(R.layout.phrase_row, null); 

     holder.imgViewLogo = (ImageView) convertView.findViewById(R.id.imgViewLogo); 
     holder.txtViewOriginal = (TextView) convertView.findViewById(R.id.txtViewOriginal); 
     holder.txtViewTranslation = (TextView) convertView.findViewById(R.id.txtViewTranslation); 
     holder.txtViewTranscription = (TextView) convertView.findViewById(R.id.txtViewTranscription); 

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


    holder.txtViewOriginal.setText(original[position]); 
    holder.txtViewTranslation.setText(translation[position]); 
    holder.txtViewTranscription.setText(transcription[position]); 

    return convertView; 
} 

}

E ho bisogno di implementare Android4 stile più selezione (premere a lungo, quindi fare clic per selezionare la voce). Quindi:

lview1 = (ListView) findViewById(R.id.listViewPhrase); 
    adapter = new PhraseCustomAdapter(this, original, translation, transcription); 
    lview1.setAdapter(adapter); 
    lview1.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); 
    lview1.setMultiChoiceModeListener(new MultiChoiceModeListener() { 

     @Override 
     public void onItemCheckedStateChanged(ActionMode mode, int position, 
               long id, boolean checked) { 
      View view; 
      if (checked){ 
       Log.v ("checked?", "YES"); 
       Log.v ("Position", Integer.toString(position)); 

       view = lview1.getChildAt(position); 
       view.setBackgroundColor(Color.LTGRAY); 


       original_list.add (adapter.getItemOriginal(position)); 
       translation_list.add (adapter.getItemTranlation(position)); 
       transcription_list.add (adapter.getItemTranscription(position)); 

       countSelected += 1; 
      } 
      if (!checked){ 
       Log.v ("checked?", "NO"); 
       Log.v ("Position", Integer.toString(position)); 


       for (int i = 0; i < original_list.size(); i++) 
       { 
        if (original_list.get(i) == adapter.getItemOriginal(position)){ 
         original_list.remove (i); 
         translation_list.remove (i); 
         transcription_list.remove (i); 
        } 
       } 
       countSelected -= 1; 
      } 


      mode.setTitle(Integer.toString(countSelected) + " " + getString(R.string.selectItem)); 
     } 

Il problema è: quando ho Premere a lungo l'oggetto (ad esempio, prima voce), l'elemento 7 è evidenziato troppo (cambiando sfondo). Quando provo a "unhighlight" evidenziato settimo elemento, l'app si blocca. Se provo a fare clic sull'ultimo elemento, l'app si arresta in modo anomalo. Ho letto alcuni articoli su come View è reso e riciclare oggetti, ma non so ogni possibile soluzione per il mio problema

UPD: uscita LogCat quando "unhighlighting" 7 ° articolo:

V/checked?(24966): YES 
V/Position(24966): 7 
Shutting down VM 
threadid=1: thread exiting with uncaught exception (group=0x2b542210) 
AndroidRuntime(24966): FATAL EXCEPTION: main 
java.lang.NullPointerException 
at com.alextee.phrases.PhraseActivity$1.onItemCheckedStateChanged(PhraseActivity.java:145) 
at android.widget.AbsListView$MultiChoiceModeWrapper.onItemCheckedStateChanged(AbsListView.java:5688) 
at android.widget.AbsListView.performItemClick(AbsListView.java:1040) 
at android.widget.AbsListView$PerformClick.run(AbsListView.java:2522) 
at android.widget.AbsListView$1.run(AbsListView.java:3183) 
at android.os.Handler.handleCallback(Handler.java:605) 
at android.os.Handler.dispatchMessage(Handler.java:92) 
at android.os.Looper.loop(Looper.java:137) 
android.app.ActivityThread.main(ActivityThread.java:4441) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:511) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 
at dalvik.system.NativeStart.main(Native Method) 
+0

puoi pubblicare lo stacktrace LogCat di quando la tua app si arresta in modo anomalo quando viene rilevato il settimo elemento? – tolgap

+0

Aggiunto alla fine del post. –

risposta

10

La vista elenco è di per sé complessa ed è anche il riciclaggio. Se guardi i video degli sviluppatori Android per la visualizzazione elenco, ne saprai di più sul riciclaggio della visualizzazione elenco e sui problemi.
Il problema nella tua app è dovuto al riciclaggio della vista elenco.
Quando si modifica lo sfondo di una voce di elenco su clic o lungo, le modifiche in background e quando questo elemento viene spostato fuori dall'area visibile del dispositivo, la vista allegata a questo elemento viene riciclata e viene assegnata a un'altra voce dell'elenco che è attualmente visibile. Quindi ora quell'elemento sarà anche evidenziato.
Questa immagine descrive il riciclaggio visualizzazione elenco:

enter image description here


Per evidenziare un elemento in un elenco si dovrebbe fare seguente:

  • Impostare onItemClickListener sulla visualizzazione elenco.
  • Nel metodo onItemClick() modificare lo sfondo della vista e salvare la posizione evidenziata corrente nella visualizzazione elenco e chiamare notifyDataSetChanged() sull'adattatore di elenco. Chiamare notifyDataSetChanged() è importante perché ridisegna gli elementi visibili correnti.

codice per la lista onItemClick dovrebbe essere qualcosa di simile:

grid[pos].setOnItemClickListener(new OnItemClickListener() { 
      @Override 
      public void onItemClick (AdapterView<?> parent, 
        View v, int position, long Id) 
      { 
        highlighted = position; //highlighted is a global variable 
        //container is the root view of the list row layout 
        LinearLayout container = (LinearLayout)v.findViewById(R.id.container); 
        container.setBackgroundResource(R.drawable.highlighted_backg); 
        mListAdapter.notifyDataSetChanged(); 

      } 
    }); 

Il GetView() metodo deve essere implementato in questo modo:

public View getView (int position, View convertView, ViewGroup parent) 
{ 
    ViewHolder holder; 

    if(convertView == null) { 
     convertView = inflater.inflate(R.layout.row_item, null); 
     holder = new ViewHolder(); 
     holder.itemName1 = (TextView)convertView.findViewById(R.id.text1); 
     ... 
     holder.container = (LineaLayout)convertView.findViewById(R.id.container); 
     convertView.setTag(holder); 
    } else { 
     holder = (ViewHolder) convertView.getTag(); 
    } 

    if(MainActivity.highlighted == position) { 
     holder.container.setBackgroundResource(R.drawable.highlighted_backg); 
    }else { 
     holder.foodItemCol1.setBackgroundResource(R.drawable.normal_back); 
    } 

    return convertView; 
} 
+0

Mi ha aiutato molto. Grazie. –

+0

Eccellente! la migliore risposta molto bella! – Kay

+0

comunque per postare il ful lcode? cercando di vedere come questo si adatta alla mia situazione attuale, ma sono un po 'perso –

1

Set il colore di sfondo dell'articolo in getView() in base allo stato selezionato. Non so se puoi ottenerlo direttamente da ListView, altrimenti potresti conservare ad es. a Set e mantieni le posizioni correntemente controllate lì. Quindi, nel getView(), cerca se la posizione passata si trova in questo set, il che significa che è selezionata e imposta lo sfondo di conseguenza. Altrimenti, imposta lo sfondo sul colore deselezionato. La successiva è importante in quanto si potrebbe avere una vista riciclata con lo sfondo impostato sul colore 'controllato'.

Un esempio per tenere traccia degli articoli selezionati è here.