2012-08-19 14 views
5

Mam niestandardowego adaptera:Android ListView zwyczaj powtarza wybór tła

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

}

I muszę wdrożyć android4 stylu wielo wyboru (długo naciśnij, a następnie kliknij, aby wybrać pozycję). Więc:

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

Problemem jest: kiedy długo-press element (na przykład pierwsza pozycja), 7. pozycja jest podświetlona zbyt (poprzez zmianę tła). Gdy próbuję "unhighlight" podświetlić 7. element, aplikacja ulega awarii. Jeśli spróbuję kliknąć najnowszy element, aplikacja ulega zawieszeniu. Czytałem kilka artykułów o tym, jak widok jest renderowany i recyklingu przedmiotów, ale nie wiem Ewentualne rozwiązanie dla mojego problemu

UPD: wyjście logcat kiedy „unhighlighting” 7th przedmiot:

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

można opublikować StackTrace logcat, kiedy Twoja aplikacja ulega awarii, gdy nie zauważysz 7. elementu? – tolgap

+0

Dodano do końca postu. –

Odpowiedz

10

Widok listy sam w sobie jest skomplikowany, a jego recykling też. Jeśli oglądasz filmy z Androidem dla widoku listy, dowiesz się więcej o recyklingu listy i jego problemach.
Problem w Twojej aplikacji wynika z recyklingu widoku listy.
Po zmianie tła elementu listy po kliknięciu lub długim kliknięciu następuje zmiana tła, a gdy przedmiot jest przewijany poza widoczny obszar urządzenia, widok dołączony do tego elementu jest ponownie przetwarzany i jest przydzielany do innego elementu listy który jest obecnie widoczny. Teraz przedmiot zostanie również podświetlony.
Ten obraz opisuje recykling widoku listy:

enter image description here


Na podkreślenie elementu w widoku listy należy wykonać następujące czynności:

  • Ustaw onItemClickListener na widoku listy.
  • W metodzie onItemClick() zmień tło widoku i zapisz bieżącą wyróżnioną pozycję w widoku listy i wywołaj metodę notifyDataSetChanged() na adapterze list. Wywołanie metody notifyDataSetChanged() jest ważne, ponieważ odrysowuje bieżące widoczne elementy.

Kod listy onItemClick powinno być coś takiego:

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

      } 
    }); 

getView() metoda powinna być realizowana tak:

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

Pomógł mi dużo. Dziękuję Ci. –

+0

Doskonale! najlepsza bardzo ładna odpowiedź! – Kay

+0

mimo to, aby opublikować pełny kod? próbując zobaczyć, jak to pasuje do mojej obecnej sytuacji, ale jestem trochę zagubiony –

1

Set kolor tła elementu w stanie getView() zgodnie z jego stanem sprawdzonym. Nie wiem, czy możesz uzyskać to bezpośrednio z ListView, w przeciwnym razie możesz zatrzymać np. a Set i przytrzymaj tam aktualnie sprawdzone pozycje. Następnie sprawdź w getView(), czy przekazana pozycja jest w tym zestawie, co oznaczałoby, że jest ona zaznaczona i odpowiednio ustawiona tło. Jeśli nie, ustaw tło na niezaznaczonym kolorze. Ta ostatnia jest ważna, ponieważ możesz otrzymać widok z recyklingu, który ma tło ustawione na "sprawdzony" kolor.

Przykład śledzenia pozycji zaznaczonych można znaleźć here.