2010-06-11 11 views
21

Ich erstelle ein Spiel und möchte dem Spieler eine einfache "Score" -Animation zeigen, wenn ihm Credits gegeben werden. Dies ist die Ansicht, die ich auf den Bildschirm werfen:Wie entferne ich eine Ansicht, wenn die Animation endet?

public class Score extends FrameLayout { 

    public Score(Context context, int score) { 
    super(context); 
    TextView txt = new TextView(context); 
    txt.setText(String.valueOf(score).toUpperCase()); 
    addView(txt); 
    Animation anim = AnimationUtils.loadAnimation(context, R.anim.score); 
    startAnimation(anim); 
    anim.setAnimationListener(animationListener); 
    } 
    private void Remove(){ 

    ViewGroup parent = (ViewGroup)getParent(); 
    parent.removeView(this); 

    } 
    private AnimationListener animationListener = new AnimationListener() { 

    @Override 
    public void onAnimationEnd(Animation animation) { 

     Remove(); 
    } 
    }; 
} 

Dieser Code ist eigentlich ziemlich gut, so lange funktioniert, wie es nur eine Punktzahl Animation auf dem Bildschirm zu einem bestimmten Zeitpunkt ist. Wenn der Spieler erneut punktet, bevor die letzte Punktzahl entfernt wurde, stürzt die App ab - wahrscheinlich, weil die zweite Punktzahl das Ereignis dazu bringt, sich selbst während der Animation zu entfernen. Ist das eine schlechte Übung bei der Verwendung von Animation? Wie würdest du damit umgehen?

Antwort

35

Ich fand auch, dass beim Entfernen einer Ansicht von seinem Eltern nach dem Anwenden einer Animation auf diese Ansicht (mit onAnimationEnd) mit NPE auf der DispatchDraw des übergeordneten Objekts abstürzt.

Die einzige Lösung, die ich gefunden habe, ist das Entfernen innerhalb eines Post-Aufrufs auszulösen. Normalerweise müssen alle UI-Änderungen im UI-Thread durchgeführt werden. Daher habe ich einen runOnUiThread-Aufruf für die Aktivität hinzugefügt, der jedoch nutzlos sein könnte (bei mir funktioniert das ohne mich).

Animation animation = AnimationUtils.loadAnimation(parentView.getContext(), animationId); 
animation.setAnimationListener(new AnimationListener() { 
    public void onAnimationStart(Animation paramAnimation) { } 
    public void onAnimationRepeat(Animation paramAnimation) { } 
    public void onAnimationEnd(Animation paramAnimation) { 
     // without the post method, the main UI crashes if the view is removed 
     parentView.post(new Runnable() { 
      public void run() { 
       // it works without the runOnUiThread, but all UI updates must 
       // be done on the UI thread 
       activity.runOnUiThread(new Runnable() { 
        public void run() { 
         parentView.removeView(view); 
        } 
       }); 
      } 
     }); 
    } 
}); 

view.setVisibility(visibility()); 
view.startAnimation(animation); 
+13

die 'runOnUiThread' ist nicht notwendig, gelöst. Durch Ausführen eines Posts in einer Ansicht wird der ausführbare Lauf im ui-Thread ausgeführt. – Macarse

+1

Danke, ich habe diesen Fehler festgestellt und die Veröffentlichung in der Ansicht hat mir erlaubt, die Ansichten zu entfernen. Es ist _weird_, dass ein Animationslistener nicht im ui-Thread läuft ... –

+5

ich denke, dass es bereits auf dem ui-Thread läuft. Ein möglicher Grund dafür, dass post() funktioniert (das ist nur eine Vermutung) ist, dass wenn Sie die Ansicht direkt in den Animations-Listener-Methoden entfernen, diese aufgerufen werden, bevor die Zeichenlogik ausgeführt wird und Sie auf die NPE treffen. Zum Beispiel kann bei jeder Ansicht der Anim-Status vor dem Zeichnen aktualisiert werden, und wenn die Animation beendet ist, werden Ihre Listener-Methoden aufgerufen. Wenn Sie ein Runnable veröffentlichen, wird es vom Looper in die Warteschlange gestellt, der wahrscheinlich keine Nachrichten verarbeiten wird, bis die Aktualisierungs-/Zeichnungslogik des View-Hierarcys für diesen Frame beendet ist. Könnte alles sein Thread – Dori

0

Bei der Verwendung von AnimationUtils.loadAnimation view.clearAnimation() mein Problem

Verwandte Themen