2015-04-21 8 views
10

Ich habe ein Problem, wenn Sie eine Animation in meinem Adapter verwenden.Verwenden von Animation in Adapter mit ViewHolder-Muster

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

     if (convertView == null) { 
      LayoutInflater inflater = LayoutInflater.from(context); 
      convertView = inflater.inflate(resource, parent, false); 
      holder = new ViewHolder(); 

      holder.newRoomView = (TextView) convertView.findViewById(R.id.newRoom); 
      convertView.setTag(holder); 
     } else { 
      holder = (ViewHolder) convertView.getTag(); 
     } 

     Room item = items.get(position); 

     // animate new rooms 
     if (item.isNewRoom()) { 
      AlphaAnimation alphaAnim = new AlphaAnimation(1.0f, 0.0f); 
      alphaAnim.setDuration(1500); 
      alphaAnim.setAnimationListener(new AnimationListener() { 
       public void onAnimationEnd(Animation animation) { 
        holder.newRoomView.setVisibility(View.INVISIBLE); 
       } 

       @Override 
       public void onAnimationStart(Animation animation) {} 

       @Override 
       public void onAnimationRepeat(Animation animation) {} 
      }); 
      holder.newRoomView.startAnimation(alphaAnim); 
     } 

     // ... 

     return convertView; 
    } 

Wenn Sie einen neuen Raum außerhalb des Adapters Hinzufügen und notifyDataSetChanged der neue Raum Aufruf korrekt animiert wird, aber wenn onAnimationEnd genannt wird, ein anderer (nicht neues Zimmer) ist ausgeblendet.

Gibt es eine Möglichkeit, den richtigen Raum versteckt zu bekommen?

+0

Warum probierst du es nicht mit 'RecyclerView'? –

+0

Posten Sie das Layout Ihres Artikels, PLZ – SilentKnight

Antwort

2

Da Sie die holder Variable in der nicht erklärt haben, getView() Methode kann ich nur annehmen, dass Sie es als Instanzvariable in Ihrer Klasse deklariert haben. Das ist Dein Problem. Wenn die Animation abgeschlossen ist, enthält die Variable holder einen Verweis auf ein völlig anderes Element.

Sie müssen eine lokale Variable verwenden, die innerhalb der getView()-Methode als final deklariert ist. Ich weiß nicht, wenn Sie diese holder Variable außerhalb der getView() Methode benötigen oder nicht, aber wenn Sie das tun, können Sie dies tun:

// animate new rooms 
    if (item.isNewRoom()) { 
     final ViewHolder holderCopy = holder; // make a copy 
     AlphaAnimation alphaAnim = new AlphaAnimation(1.0f, 0.0f); 
     alphaAnim.setDuration(1500); 
     alphaAnim.setAnimationListener(new AnimationListener() { 
      public void onAnimationEnd(Animation animation) { 
       holderCopy.newRoomView.setVisibility(View.INVISIBLE); 
      } 

      @Override 
      public void onAnimationStart(Animation animation) {} 

      @Override 
      public void onAnimationRepeat(Animation animation) {} 
     }); 
     holder.newRoomView.startAnimation(alphaAnim); 
    } 

Dies wird natürlich nicht funktionieren, wenn die Animation so lange dauert, dass Die Aussicht wurde in der Zwischenzeit recycelt.

0

Es ist wahrscheinlich wegen des Recycling-Mechanismus des Listview. Markieren Sie die animierte Ansicht und verwenden Sie findViewByTag, um sie abzurufen onAnimationEnd. Z.B.

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

    if (convertView == null) { 
     LayoutInflater inflater = LayoutInflater.from(context); 
     convertView = inflater.inflate(resource, parent, false); 
     holder = new ViewHolder(); 

     holder.newRoomView = (TextView) convertView.findViewById(R.id.newRoom); 
     convertView.setTag(holder); 
    } else { 
     holder = (ViewHolder) convertView.getTag(); 
    } 

    Room item = items.get(position); 

    // animate new rooms 
    if (item.isNewRoom()) { 
     AlphaAnimation alphaAnim = new AlphaAnimation(1.0f, 0.0f); 
     alphaAnim.setDuration(1500); 
     alphaAnim.setAnimationListener(new AnimationListener() { 
      public void onAnimationEnd(Animation animation) { 
       View view = convertView.findViewWithTag(position); 
       if (view != null) { 
        view.setVisibility(View.INVISIBLE); 
       } 

      } 

      @Override 
      public void onAnimationStart(Animation animation) {} 

      @Override 
      public void onAnimationRepeat(Animation animation) {} 
     }); 
     holder.newRoomView.startAnimation(alphaAnim); 
     holder.newRoomView.setTag(position); 
    } 

    // ... 

    return convertView; 
} 
0

Denken Sie daran, müssen Sie immer für Dinge wie diese eine andere Äußerung. Sonst wird auch alles andere, das denselben Ansichtshalter verwendet, unsichtbar.

if (item.isNewRoom()) { 
     AlphaAnimation alphaAnim = new AlphaAnimation(1.0f, 0.0f); 
     alphaAnim.setDuration(1500); 
     alphaAnim.setAnimationListener(new AnimationListener() { 
      public void onAnimationEnd(Animation animation) { 
       holder.newRoomView.setVisibility(View.INVISIBLE); 
      } 

      @Override 
      public void onAnimationStart(Animation animation) {} 

      @Override 
      public void onAnimationRepeat(Animation animation) {} 
     }); 
     holder.newRoomView.startAnimation(alphaAnim); 
    }else{ 
     holder.newRoomView.setVisibility(View.VISIBLE); 
    } 
1
if (item.isNewRoom()) { 

     // store view reference first 
     final View newRoomView = holder.newRoomView; 
     ... 
     alphaAnim.setAnimationListener(new AnimationListener() { 
      public void onAnimationEnd(Animation animation) { 

       // hide exactly this view when animation ends 
       newRoomView.setVisibility(View.INVISIBLE); 
      } 
     ... 
    } 
0

OK. Ich habe vor dieses Problem hatte, und dies ist wahrscheinlich ein Android-Bug:

Sie verwenden inneren Objekte der Animation Zuhörer einzustellen:

alphaAnim.setAnimationListener(new AnimationListener(){/*bla bla bla*/}); 

Ändern Sie den obigen Code zu so etwas wie dieses:

AnimationListener myListener = new AnimationListener(){/*bla bla bla*/}; 
alphaAnim.setAnimationListener(myListener); 

Ziemlich verrückt eine Lösung, ich weiß, aber es hat mir den Arsch in mehreren ähnlichen Gelegenheiten gespeichert.

+0

Leider. dies scheint nicht zu funktionieren für mich :( – Chris

+0

Diese Antwort ist nutzlos. Der Code, den Sie vorgeschlagen haben, ist genau der gleiche wie der Code, den Sie ersetzen. Sie sind immer noch eine anonyme Klasse, die gleiche wie vor zu schaffen. Der Compiler kompiliert beide Code-Schnipsel auf genau die gleiche Sache –

+0

@ David Wasser. das hat für mich in der Vergangenheit gearbeitet Sind Sie 100% sicher, dass die Codes genau auf Android werden die gleichen sein – Behnam

Verwandte Themen