Animation Android: attendre jusqu'à la fin?

je voudrais attendre jusqu'à ce qu'une animation soit terminée* dans une ImageView Android avant de poursuivre l'exécution du programme, Quelle est la bonne façon de le faire?

  • (dans ce contexte, "fini" signifie qu'elle traverse l'ensemble de ses cadres exactement une fois et s'arrête sur la dernière. Je ne sais pas si cette animation sera un android:oneshot=" true " animation parce que je l'utiliserai plusieurs fois, mais il ne sera pas exécuté en continu mais par intermittence)

Recherche/ Suppositions:

A. Au fond, ma question semble être une question de fil de Java parce que L'Android AnimationDrawable implements Java.lang.Runnable . Peut-être que les fils sont la solution. Peut-être la réponse inclura-t-elle rejoindre ?

B. L'approche des autres semble avoir été d'utiliser AnimationListener , cela semble difficile et inutilement complexe pour mes besoins simples. En plus, je ne sais pas vraiment comment faire.

C. La classe AnimationDrawable a une méthode (booléenne) isRunning qui pourrait probablement être utilisée dans une boucle while(i.e. while (anim.isRunning ()) {wait (100ms)}). Mais j'ai le pressentiment que c'est la mauvaise approche. Bien que quelque chose de similaire semble être mentionné dans le tutorial de la concurrence

"151930920 Extrait De Code",

   this.q_pic_view.setImageResource(0);
    this.q_pic_view.setBackgroundResource(R.drawable.animation_test);
    AnimationDrawable correct_animation = (AnimationDrawable) this.q_pic_view.getBackground();
    correct_animation.start();

    //here I tried to implement option C but it didn't work
    while(correct_animation.isRunning()){
        try {
           Thread.sleep(20);
        } catch (InterruptedException e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
        }
    }

Animation

<?xml version="1.0" encoding="utf-8"?>
<animation-list android:id="@+id/AnimTest" android:oneshot="true" xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:drawable="@drawable/animtest001" android:duration="33"/>
  <item android:drawable="@drawable/animtest002" android:duration="100"/>
  <item android:drawable="@drawable/animtest003" android:duration="66"/>
  <item android:drawable="@drawable/animtest004" android:duration="66"/>
  <item android:drawable="@drawable/animtest005" android:duration="33"/>
  <item android:drawable="@drawable/animtest006" android:duration="66"/>
  <item android:drawable="@drawable/animtest007" android:duration="33"/>
  <item android:drawable="@drawable/animtest008" android:duration="66"/>
  <item android:drawable="@drawable/animtest009" android:duration="100"/>
  <item android:drawable="@drawable/animtest010" android:duration="100"/>
</animation-list>

une façon Possible d'obtenir l'effet désiré, bien qu'elle ne soit pas une réponse à ma question, Est de retarder l'exécution d'un autre code en faisant quelque chose comme ceci:

int duration = 0;
//Add all of the frames together
for (int i=0; i<my_animation.getNumberOfFrames(); i++){
    duration = duration + correct_animation.getDuration(i);
    }
//delay the execution 
Handler handler = new Handler();
handler.postDelayed(new Runnable(){
    public void run() {
       DoYourNextStuff();
        }
}, duration); //delay is here

Edit: il y a plusieurs façons de résoudre ce problème, la réponse donnée résout probablement le problème Je ne l'ai pas testé , mais j'ai fini juste en attendant le temps correct (au début), j'ai changé pour utiliser une tâche async (qui a une méthode handler pour terminer) et j'ai lancé mon animation dans l'appel de mise à jour de la tâche async directement. Dans la dernière itération, j'utilise une vue de surface filetée pour exécuter l'animation. Cette dernière voie est de loin la plus rapide et la meilleure (pour des raisons autres que ceux qui ont été interrogés dans ce post). J'espère que cela aide quelqu'un.

27
demandé sur Community 2011-03-16 08:16:15

4 réponses

vous suggère

  • créer un objet pour encapsuler la "animation" vie
  • dans l'objet, vous aurez un fil ou une minuterie
  • fournit des méthodes pour start() l'animation et awaitCompletion()
  • utilisez un private final Object completionMonitor pour suivre l'achèvement, synchronize dessus, et utilisez wait() et notifyAll() pour coordonner le awaitCompletion()
"1519140920 extrait de Code":

final class Animation {

    final Thread animator;

    public Animation()
    {
      animator = new Thread(new Runnable() {
        // logic to make animation happen
       });

    }

    public void startAnimation()
    {
      animator.start();
    }

    public void awaitCompletion() throws InterruptedException
    {
      animator.join();
    }
}

vous pouvez également utiliser un ThreadPoolExecutor avec un seul thread ou ScheduledThreadPoolExecutor , et capturer chaque image de l'animation comme un Callable . Soumettre la séquence de Callable s et en utilisant invokeAll() ou un CompletionService pour bloquer votre thread intéressé jusqu'à ce que l'animation est complète.

10
répondu andersoj 2011-03-16 05:51:11

la façon la plus facile serait de poster un (retardé) exécutable sur le thread de L'interface utilisateur:

Animation fadeout = new AlphaAnimation(1.f, 0.f);
fadeout.setDuration(500);
view.startAnimation(fadeout);
view.postDelayed(new Runnable() {
    @Override
    public void run() {
        view.setVisibility(View.GONE);
    }
}, 500);

Qui fera le travail sans douleur. Et de ne jamais (jamais, jamais, jamais!) essayer de bloquer le fil UI dans Android. Si vous le faisiez, le téléphone gèle et vous ne verriez pas l'animation de toute façon. Si vous avez besoin d'attendre un certain temps, utilisez un autre fil.

48
répondu netzpurist 2011-11-05 01:41:35

utilisez L'écouteur D'Animation pour écouter les crochets du cycle de vie de l'animation.

Animation fadeout = new AlphaAnimation(1.f, 0.f);
fadeout.setDuration(500);    
final View viewToAnimate = view;
fadeout.setAnimationListener(new AnimationListener(){

   @Override
   public void onAnimationStart(Animation animation){}

   @Override
   public void onAnimationRepeat(Animation animation){}

   @Override
   public void onAnimationEnd(Animation animation){
       viewToAnimate.setVisibility(View.GONE);
   }
});
view.startAnimation(fadeout);
37
répondu helder.vasc 2014-01-14 19:47:11

Hi une autre alternative est d'utiliser Objectanimateur . Comme d'autres l'ont mentionné, vous devrez utiliser un Listner

//get an image resource    
ImageView imgView = (ImageView) findViewById(R.id.some_image);      
//create and init an ObjectAnimator  
ObjectAnimator animation;
animation = ObjectAnimator.ofFloat(imgView, "rotationY", 0.0f, 360f);

//set the duration of each iteration
animation.setDuration(1500);
//set number of iterations
animation.setRepeatCount(1);
//set setInterpolator 

animation.setInterpolator(new AccelerateDecelerateInterpolator());
//Add a listner to check when the animation ends
animation.addListener(new AnimatorListenerAdapter() {
       @Override
       public void onAnimationEnd(Animator animation) {
                //postFirstAnimation(): This function is called after the animation ends
                postFirstAnimation();
       }
});
//start the animation
animation.start();
2
répondu Pranaysharma 2015-02-06 09:31:32