1. Nimm jetzt an unserem 2. ADVENT-Gewinnspiel teil - Alle Informationen findest Du hier!

Fehlerhafte Selektion in der Liste

Dieses Thema im Forum "Android App Entwicklung" wurde erstellt von Butch78, 26.01.2012.

  1. Butch78, 26.01.2012 #1
    Butch78

    Butch78 Threadstarter Junior Mitglied

    Beiträge:
    28
    Erhaltene Danke:
    0
    Registriert seit:
    06.12.2011
    Hi Leute,

    mich macht meine ListView noch irre :crying:. Ich versuchte nun schon einige Zeit folgendes Problem zu lösen. Habe eine Liste der eine Textview liegt. Sobald ich ein Objekt anklicke, soll sich dessen Background ändern. Das klappt auch schon alles.

    Aber Probleme gibt es wenn ich in meiner Liste scrollen muss. Wenn ich z.B. das erste Element selektiere und scrolle dann nach unten, ist auch automatisch das nächste sichtbare Element mit selektiert.

    Hier mal mein Code:

    Code:
    [LEFT]public View getView(final int position, View convertView, ViewGroup parent) {
       View view = null;
       if (convertView == null) {
        LayoutInflater inflator = context.getLayoutInflater();
        view = inflator.inflate(R.layout.condiment_list_items, null);
        final ViewHolder viewHolder = new ViewHolder();
        //viewHolder.icon = (ImageView)view.findViewById(R.id.iv_loeschen_icon);
        viewHolder.text = (TextView) view.findViewById(R.id.tx_condiment_list_items);      
        viewHolder.text.setTag(list.get(position));   
        viewHolder.text.setBackgroundDrawable(null);
        viewHolder.text.setOnClickListener(new OnClickListener() {    
         @Override   
         public void onClick(View v) {     
          BasketItem item = (BasketItem) 
            v.getTag();
          if(item.getKorb() == 0){
           item.setKorb(1);
           v.setBackgroundDrawable(getResources().getDrawable(R.drawable.strike_out));
           Toast.makeText(mContext, item.getZutat(), Toast.LENGTH_LONG).show();
          }else{
           item.setKorb(0);
           v.setBackgroundDrawable(null);
          }             
         }
        });
        
      
        viewHolder.text.setOnLongClickListener(new OnLongClickListener() {    
         @Override
         public boolean onLongClick(View v) {
          ArrayList<BasketItem> list = new ArrayList<BasketItem>();
          BasketItem item = (BasketItem)  viewHolder.text.getTag();
          list.add(item);
          Intent intent = new Intent(mContext, ContextMenuHelperCondimentList.class);
          intent.putParcelableArrayListExtra ("list", (ArrayList<? extends Parcelable>) list); 
          startActivity(intent);
          return true;
         }
        });
        view.setTag(viewHolder);
        viewHolder.text.setTag(list.get(position));
        
        if(list.get(position).getKorb()==1){
         viewHolder.text.setBackgroundDrawable(getResources().getDrawable(R.drawable.strike_out));
        }else{
         viewHolder.text.setBackgroundDrawable(null);
        }   
        
       } else {
        view = convertView;
       }
       ViewHolder holder = (ViewHolder) view.getTag();
       holder.text.setText(list.get(position).getZutat());
       holder.text.setTypeface(mFontNormal);
       return view;
      }
     }  
     
    
    Viele Grüße

    Butch
    [/LEFT]
     
    Zuletzt bearbeitet: 27.01.2012
  2. Butch78, 27.01.2012 #2
    Butch78

    Butch78 Threadstarter Junior Mitglied

    Beiträge:
    28
    Erhaltene Danke:
    0
    Registriert seit:
    06.12.2011
    Keiner eine Idee?

    Gruß
     
  3. the_alien, 27.01.2012 #3
    the_alien

    the_alien Android-Lexikon

    Beiträge:
    1,559
    Erhaltene Danke:
    184
    Registriert seit:
    04.05.2009
    Der View wird wiederverwendet.Änderst du also die Hintergrundfarbe, so musst du dafür sorgen, dass sie wieder zurückgeändert wird in getView().

    PS: Formatiere doch die Codeschnipsel nächstes mal für bessere Lesbarkeit.
     
  4. Butch78, 27.01.2012 #4
    Butch78

    Butch78 Threadstarter Junior Mitglied

    Beiträge:
    28
    Erhaltene Danke:
    0
    Registriert seit:
    06.12.2011
    Hi,

    sorry hast Recht da muss ich besser aufpassen...

    Was genau meinst du das mit zurücksetzen in getView? Per Googlesuche hatte ich irgendwo das gleiche Problem gefunden und dort wurde gesagt mal sollte den Hintergrund in getView auf null setzen. Das habe ich bereits drin und hat aber leider keine Auswirkung gezeigt:

    Code:
    [SIZE=2][LEFT]viewHolder.text.setBackgroundDrawable(null);
        viewHolder.text.setOnClickListener(new OnClickListener() {    
         @Override   
         public void onClick(View v) {     
          BasketItem item = (BasketItem) 
            v.getTag();
          if(item.getKorb() == 0){
           item.setKorb(1);
           v.setBackgroundDrawable(getResources().getDrawable(R.drawable.strike_out));
          }else{
           item.setKorb(0);
           v.setBackgroundDrawable(null);
          }             
         }
        });[/SIZE][/LEFT]
    [SIZE=2]
    [/SIZE] 
    

    Gruß
    Butch
     
  5. strider, 27.01.2012 #5
    strider

    strider Erfahrener Benutzer

    Beiträge:
    208
    Erhaltene Danke:
    45
    Registriert seit:
    30.09.2011
    Phone:
    Nexus S
    else {
    view = convertView;
    }

    das Ding kurz vor dem Ende mein er. Wenn eine View aus dem sichtbaren Bereich rauskommt, kriegst du sie in getView als convertView wieder zum recyclen.
    Du setzt kurz vor Ende von getView die alte View als neue View ein die du dann zurücklieferst ohne nochmal die Hintergrundfarbe zu ändern. Wenn also die alte View die zum recyclen ankommt und eine Hintergrundfarbe gesetzt hat läuft sie unverändert durch dein Code durch.
     
  6. Butch78, 27.01.2012 #6
    Butch78

    Butch78 Threadstarter Junior Mitglied

    Beiträge:
    28
    Erhaltene Danke:
    0
    Registriert seit:
    06.12.2011
    Hi,

    danke soweit. Jetzt werden zwar keine doppelten Items mehr selektiert, aber jetzt gehen beim scrollen leider die bereits ausgewählten Items verloren. Ich setze nun den Hintergrund der alten view zurück und übergebe die alte view dann der neuen.

    else​
    {
    ViewHolder holder = (ViewHolder) convertView.getTag();
    holder.
    text.setBackgroundDrawable(null);
    view = convertView;

    }

    Effekt nun: Ich selektiere das erste Element und scroller runter und wieder hoch => erstes Element hat die Selektion verloren.

    Gruß


     
  7. the_alien, 27.01.2012 #7
    the_alien

    the_alien Android-Lexikon

    Beiträge:
    1,559
    Erhaltene Danke:
    184
    Registriert seit:
    04.05.2009
    OK, langsam zum mitschreiben:
    Der View wird recycled!

    DU musst dich darum kümmern, dass die Farbe für die Selektion in getView() richtig gesetzt wird und zwar für "selektiert" UND für "nicht selektiert".

    Woher soll das System es sonst wissen, wenn du es ihm nicht mitteilst?
     
  8. Butch78, 27.01.2012 #8
    Butch78

    Butch78 Threadstarter Junior Mitglied

    Beiträge:
    28
    Erhaltene Danke:
    0
    Registriert seit:
    06.12.2011
    Das mach ich doch schon: In meinem Clicklistener nehm ich mir das passende Element aus meiner ArrayListe und setze entsprechend den Status ( item.setKorb(0/1). Diesen Status frage ich weiter unten wieder ab und setze den Hintergrund.

    Code:
    public void onClick(View v) {          [SIZE=2]
          BasketItem item = [/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]mBasketList[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2].get(position);
    [/SIZE]      if(item.getKorb() == 0){
           item.setKorb(1);
           v.setBackgroundDrawable(getResources().getDrawable(R.drawable.strike_out));
           Toast.makeText(mContext, item.getZutat(), Toast.LENGTH_LONG).show();
          }else{
           item.setKorb(0);
           v.setBackgroundDrawable(null);
          }             
         }
    

    Code:
    
    [SIZE=2] 
    [LEFT]BasketItem item = [/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]mBasketList[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2].get(position);
    [/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]if[/B][/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2](item.getKorb()==1){
           viewHolder.[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]text[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2].setBackgroundDrawable(getResources().getDrawable  (R.drawable.[/SIZE][I][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]strike_out[/I][/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]));
    }[/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]else[/B][/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]{
          viewHolder.[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]text[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2].setBackgroundDrawable([/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]null[/B][/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]);
    } [/LEFT]
    
    [/SIZE]
     
  9. swordi, 27.01.2012 #9
    swordi

    swordi Gewerbliches Mitglied

    Beiträge:
    3,389
    Erhaltene Danke:
    441
    Registriert seit:
    09.05.2009
    dann mach statt null mal nen echten wert ( transparent vielleicht )

    vielleicht wird null ja einfach ignoriert ?
     
  10. the_alien, 27.01.2012 #10
    the_alien

    the_alien Android-Lexikon

    Beiträge:
    1,559
    Erhaltene Danke:
    184
    Registriert seit:
    04.05.2009
    Nein, du setzt den Hintergrund nur wenn der convertView == null ist.
    Respektive fragst du deinen Korb nur ab wenn der convertView null ist, wenn er != null ist dann wird der Hintergrund einfach zurückgesetzt.
     
  11. Butch78, 27.01.2012 #11
    Butch78

    Butch78 Threadstarter Junior Mitglied

    Beiträge:
    28
    Erhaltene Danke:
    0
    Registriert seit:
    06.12.2011
    Sorry Leute aber es will einfach nicht... Tut mir leid wenn ich euch schon nerve, aber ich weiß echt nicht weiter:

    hier mein aktueller Code:

    Code:
     public View getView(final int position, View convertView, ViewGroup parent) {
       View view = null;
       if (convertView == null) {
        LayoutInflater inflator = context.getLayoutInflater();
        view = inflator.inflate(R.layout.condiment_list_items, null);
        final ViewHolder viewHolder = new ViewHolder();
        //viewHolder.icon = (ImageView)view.findViewById(R.id.iv_loeschen_icon);
        viewHolder.text = (TextView) view.findViewById(R.id.tx_condiment_list_items);      
        viewHolder.text.setTag(list.get(position));   
        viewHolder.text.setOnClickListener(new OnClickListener() {    
         @Override   
         public void onClick(View v) {     
          BasketItem item = mBasketList.get(position);
          if(item.getKorb() == 0){
           item.setKorb(1);
           v.setBackgroundDrawable(getResources().getDrawable(R.drawable.strike_out));
          }else{
           item.setKorb(0);
           v.setBackgroundColor(0x00000000); 
          }             
         }
        });
     
     
        viewHolder.text.setOnLongClickListener(new OnLongClickListener() {    
         @Override
         public boolean onLongClick(View v) {
          ArrayList<BasketItem> list = new ArrayList<BasketItem>();
          BasketItem item = (BasketItem)  viewHolder.text.getTag();
          list.add(item);
          Intent intent = new Intent(mContext, ContextMenuHelperCondimentList.class);
          intent.putParcelableArrayListExtra ("list", (ArrayList<? extends Parcelable>) list); 
          startActivity(intent);
          return true;
         }
        });
        view.setTag(viewHolder);    
        viewHolder.text.setTag(list.get(position));  
        BasketItem item = (BasketItem) 
          viewHolder.text.getTag();  
        if(item.getKorb()==1){
         viewHolder.text.setBackgroundDrawable(getResources().getDrawable(R.drawable.strike_out));
        }else{
         viewHolder.text.setBackgroundColor(0x00000000); 
        }       
       } else {
        view = convertView;    
        ViewHolder holder = (ViewHolder) view.getTag();
        BasketItem item = mBasketList.get(position); 
        if(item.getKorb()==0){
         holder.text.setBackgroundColor(0x00000000);  
        }else{
         holder.text.setBackgroundDrawable(getResources().getDrawable(R.drawable.strike_out));
        }
       }
       ViewHolder holder = (ViewHolder) view.getTag();
       holder.text.setTag(list.get(position));   
       holder.text.setText(list.get(position).getZutat());
       holder.text.setTypeface(mFontNormal);
       return view;
      }
     }  
    
    Ich prüfe den Status wenn convertView == null und umgekehrt, aber das Scrollproblem besteht weiterhin. Was mir beim debuggen gerade aufgefallen ist, das nach dem Scrollen:

    BasketItem item = mBasketList.get(position); in meiner
    onClick Methode nicht das richtige Element gibt. position scheint hier nicht zu stimmen...

    Gruß
     
  12. Butch78, 27.01.2012 #12
    Butch78

    Butch78 Threadstarter Junior Mitglied

    Beiträge:
    28
    Erhaltene Danke:
    0
    Registriert seit:
    06.12.2011
    Ok ich glaube mit
    BasketItem item = (BasketItem) viewHolder.​
    text

    .getTag();

    in der onClick-Methode gehts nun...

    Danke euch noch für eure Unterstützung:thumbup:
     
  13. the_alien, 27.01.2012 #13
    the_alien

    the_alien Android-Lexikon

    Beiträge:
    1,559
    Erhaltene Danke:
    184
    Registriert seit:
    04.05.2009
    Ok, hier mal die richtige Variante:

    Code:
    public View getView(final int position, View convertView, ViewGroup parent) {
       View view = null;
       if (convertView == null) {
        LayoutInflater inflator = context.getLayoutInflater();
        view = inflator.inflate(R.layout.condiment_list_items, null);
        final ViewHolder viewHolder = new ViewHolder();
        //viewHolder.icon = (ImageView)view.findViewById(R.id.iv_loeschen_icon);
        viewHolder.text = (TextView) view.findViewById(R.id.tx_condiment_list_items);      
        viewHolder.text.setTag(list.get(position));   
        [color=red]//Die Listener werden nur bei einem neuen View angehängt, [b]SIE WERDEN RECYCLED![/b][/color]
        view.setTag(viewHolder);    
        viewHolder.text.setTag(list.get(position));  
        BasketItem item = (BasketItem) 
          viewHolder.text.getTag();  
        [color=red]//if anweisung hier weg[/color]
       } else {
        view = convertView;    
        ViewHolder holder = (ViewHolder) view.getTag();
        BasketItem item = mBasketList.get(position); 
        [color=red]//if Anweisung hier ist unnütz[/color]
       }
       [color=green]//if Anweisung hier hin
       if(item.getKorb()==1){
         viewHolder.text.setBackgroundDrawable(getResources().getDrawable(R.drawable.strike_out));
        }else{
         viewHolder.text.setBackgroundColor(0x00000000); 
        }       
        //Ausserdem müssen hier noch die Listener hin
    [/color]
    
       ViewHolder holder = (ViewHolder) view.getTag();
       holder.text.setTag(list.get(position));   
       holder.text.setText(list.get(position).getZutat());
       holder.text.setTypeface(mFontNormal);
       return view;
      }
     }
     

Diese Seite empfehlen