33

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

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

研究/猜测:

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

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

C. AnimationDrawable类有一个(boolean) isRunning 方法,该方法可能在while 循环中使用(即while(anim.isRunning()){wait(100ms)})。但我有一种直觉,这是错误的方法。虽然并发教程中似乎提到了类似的东西

代码片段

   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

4 回答 4

56

The easiest way would be to post a (delayed) Runnable to the UI thread:

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

That will do the job painlessly. And never (never, never, never!) try to block the UI thread in Android. If you did so, the phone freezes and you would not see the animation anyway. If you need to wait some time, use another thread.

于 2011-11-05T01:41:35.043 回答
47

使用动画监听器来监听动画生命周期钩子。

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);
于 2014-01-14T19:47:11.713 回答
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();
    }
}

您还可以将 aThreadPoolExecutor与单个线程一起使用,或者ScheduledThreadPoolExecutor将动画的每一帧捕获为Callable. 提交Callables 的序列并使用invokeAll()orCompletionService来阻塞您感兴趣的线程,直到动画完成。

于 2011-03-16T05:45:48.103 回答
4

您好,另一种选择是使用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();
于 2015-02-06T09:07:31.343 回答