Android动画:等到完成?

时间:2011-03-16 05:16:15

标签: java android concurrency android-animation

我想在继续执行程序之前等到Android ImageView中的动画结束*,这样做的正确方法是什么?

  • (在这种情况下,“完成”意味着它只运行一次所有帧并停在最后一帧。我不清楚这个动画是否会是一个android:oneshot =“true”动画,因为我会多次使用它,但它不会连续运行而是间歇性运行)

研究/猜测:

一个。从本质上讲,我的问题似乎是一个Java线程问题,因为Android AnimationDrawable实现了Java.lang.Runnable。也许线程是解决方案。答案可能包括join

B中。其他人的方法似乎是使用AnimationListener,这对于我的简单需求来说似乎很困难且不必要地复杂。另外,我不确定该怎么做。

℃。 AnimationDrawable类有一个(布尔)isRunning方法,它可能在while循环中使用(即while(anim.isRunning()){wait(100ms)})。但我有一种直觉,认为这是错误的做法。虽然concurrency tutorial

中似乎提到了类似的内容

代码段

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

动画

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

实现预期效果的一种可能方法,虽然不是我的问题的答案,但是通过这样做来延迟执行更多代码:

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

编辑:有很多方法可以解决这个问题,给出的答案可能确实解决了问题我没有测试它,但我最后只是等待了正确的时间(起初),然后我改为使用异步任务(具有完成的处理程序方法)并直接在异步任务的updateProgress调用中运行我的动画。在最后一次迭代中,我使用线程表面视图来运行动画。最后一种方式是迄今为止最快和最好的方式(出于那些在本文中提到的其他原因)。我希望它有所帮助。

4 个答案:

答案 0 :(得分:50)

最简单的方法是将(延迟的)Runnable发布到UI线程:

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

这将无痛苦地完成工作。从来没有(永远,永远,永远!)尝试阻止Android中的UI线程。如果您这样做,手机会冻结,无论如何您都不会看到动画。 如果您需要等待一段时间,请使用另一个线程。

答案 1 :(得分:40)

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

答案 2 :(得分:9)

建议你

  • 创建一个对象以封装“动画”生命周期
  • 在对象中,您将拥有一个线程或一个计时器
  • start()动画和awaitCompletion()
  • 提供方法
  • 使用private final Object completionMonitor字段跟踪完成情况synchronize,然后使用wait()notifyAll()来协调awaitCompletion()

代码段:

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

您还可以将ThreadPoolExecutor与单个帖子或ScheduledThreadPoolExecutor一起使用,并将动画的每个帧捕获为Callable。提交Callable的序列并使用invokeAll()CompletionService来阻止您感兴趣的帖子,直到动画完成。

答案 3 :(得分:2)

另一种选择是使用ObjectAnimator。再次像其他人提到的那样你必须使用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();