2011-03-16 23 views
26

Me gustaría esperar hasta que finalice una animación * en un Android ImageView antes de continuar la ejecución del programa, ¿cuál es la forma correcta de hacerlo?Android Animation: ¿esperar hasta que termine?

  • (en este contexto "terminado" significa que se ejecuta a través de todos sus marcos exactamente una hora y se detiene en el último estoy claro si esta animación será un androide:.-Tiro = "true" animación porque me va a utilizar varias veces, pero no se llevará a cabo de forma continua, pero de forma intermitente)

Investigación/las suposiciones:

A. en el fondo de mi pregunta parece ser una pregunta hebra Java porque los implementos Android AnimationDrawableJava.lang.Runnable. Entonces, quizás los hilos son la solución. Tal vez la respuesta incluirá join?

B. El enfoque de otros parece haber sido utilizar AnimationListener, esto parece difícil e innecesariamente complejo para mis necesidades simples. Además, no estoy exactamente seguro de cómo hacerlo.

C. La clase AnimationDrawable tiene un método (booleano) isRunning que probablemente podría usarse en un ciclo while (es decir, while (anim.isRunning()) {wait (100ms)}). Pero tengo la corazonada de que este es el enfoque equivocado. Aunque algo similar parece ser mencionado en la concurrency tutorial

Fragmento de código

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

Animación

<?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> 

una forma posible de conseguir el efecto deseado, aunque no es una respuesta a mi pregunta, es retrasar la ejecución de código adicional haciendo algo como esto:

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 

Editar: Hay muchas maneras de resolver este problema, la respuesta dada probablemente resuelve el problema No lo probé, pero terminé esperando la cantidad correcta de tiempo (al principio), luego cambié a utilizando una tarea asíncrona (que tiene un método de control para completar) y ejecuté mi animación directamente en la llamada update progress de la tarea asincrónica. En la última iteración, estoy usando una vista de superficie enhebrada para ejecutar la animación. Esta última forma es, con mucho, la más rápida y la mejor (por razones distintas a las preguntadas en esta publicación). Espero que esto ayude a alguien.

+0

¿cuánto tiempo lleva terminar la animación ...? –

+0

CapDroid si suma todos los enteros en el fragmento de xml anterior obtendrá la duración total de la animación. Pero estoy buscando una solución general, así que eso no me ayudaría en este caso. – tjb

+0

Simplemente prueba este Thread.sleep (663); 663 = Tiempo total de animación ... –

Respuesta

11

sugerimos que

  • crear un objeto para encapsular la "animación" de por vida
  • En el objeto, tendrá un hilo o un temporizador
  • Proporcionar métodos a start() la animación y awaitCompletion()
  • Utilice un campo private final Object completionMonitor para realizar un seguimiento de la finalización, synchronize en él, y utilice wait() y notifyAll() para coordinar el awaitCompletion()

Código fragmento:

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

También podría utilizar un ThreadPoolExecutor con un solo hilo o ScheduledThreadPoolExecutor, y capturar cada cuadro de la animación como Callable. Envíe la secuencia de Callable sy usando invokeAll() o CompletionService para bloquear el hilo interesado hasta que se complete la animación.

45

La forma más fácil sería publicar en un (retardada) Ejecutable al hilo de interfaz de usuario:

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

que va a hacer el trabajo sin dolor. Y nunca (nunca, nunca, nunca!) Intente bloquear el hilo de UI en Android. Si lo hiciste, el teléfono se congela y no verías la animación de todos modos. Si necesita esperar un tiempo, use otro hilo.

+0

Excelente respuesta, aunque tuve un pequeño problema al hacer trabajos pesados ​​/ de bases de datos en ejecución() junto con las condiciones de si la animación ha finalizado. 'animation.hasEnded()' Puede que no sea verdadero todo el tiempo. El aumento de los milisegundos retrasados ​​en 'postDelayed' que la duración de la animación, resolvió el problema :) – Wesley

+0

¡Este código era épico, tan pequeño y funciona como un encanto! ¡¡Gracias por publicar!! – deucalion0

+0

Realmente no creo que esta sea una buena solución. los valores de codificación difícil raramente lo son. – katzenhut

35

Use el oyente de Animación para escuchar los enganches del ciclo de vida de la animación.

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); 
+3

no tengo idea de cómo esta no es la respuesta más votada. es tan obviamente correcto. de todos modos, +1 de mi parte. – katzenhut

+1

@katzenhut porque la respuesta es incorrecta en el contexto actual. El OP está usando un AnimationDrawable que ni siquiera se deriva de la animación. Entonces, esta respuesta es correcta si está utilizando una animación derivada de la clase de Animación, pero no es correcta para AnimationDrawable. AnimationDrawable no tiene devoluciones de llamada como la clase de Animación con respecto a su ciclo de vida. – AgentKnopf

+1

@Zainodis - Las connotaciones de nombres extraños en Android nunca dejan de sorprenderme ... pero tienes razón. ¡Gracias por la aclaración! – katzenhut

1

Hola, otras alternativas es usar ObjectAnimator. Una vez más, como otros mencionaron, tendrías que usar 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(); 
Cuestiones relacionadas