2011-03-16 109 views
26

我想在繼續執行程序之前等待動畫完成*在Android ImageView中,執行此操作的正確方法是什麼?Android動畫:等到完成?

  • (在這種情況下,「完成」意味着它完全貫穿其所有幀並停在最後一幀。我不清楚這個動畫是否爲android:oneshot =「true」動畫,因爲我會多次使用它,但它不會連續運行,但間歇性)

研究/猜測:

A.在心臟,我的問題似乎是一個Java線程的問題,因爲Android的AnimationDrawable工具Java.lang.Runnable。所以也許線程是解決方案。也許答案將包括join

B.其他人的做法似乎是使用AnimationListener,這似乎是困難和不必要的複雜,我的簡單需求。另外我不確定如何去做。

C. AnimationDrawable類有一個(boolean)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調用中運行我的動畫。在最後一次迭代中,我使用螺紋表面視圖來運行動畫。最後一種方式是最快和最好的(因爲在這篇文章中被問到的其他原因)。我希望它能幫助別人。

+0

動畫完成需要多少時間..? – 2011-03-16 05:48:54

+0

CapDroid如果您將上述xml片段中的所有整數相加,您將獲得動畫的總持續時間。但是我正在尋找一個通用的解決方案,以免在這種情況下幫助我。 – tjb 2011-03-16 18:10:48

+0

試試這個Thread.sleep(663); 663 =動畫總時間.. – 2011-03-17 04:57:50

回答

11

建議你

  • 創建一個對象來封裝「動畫」終身
  • 在對象,你就會有一個線程或計時器
  • 提供方法來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阻止感興趣的線程,直到動畫完成。

45

最簡單的方法是發佈(延遲)可運行到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線程。如果你這樣做了,電話就會凍結,反正你也看不到動畫。 如果您需要等待一段時間,請使用另一個線程。

+0

很好的答案,儘管我在run()中執行繁重/數據庫工作時遇到了一個小問題,以及動畫結束的條件。 'animation.hasEnded()'它可能不會一直返回true。在動畫持續時間內延長'postDelayed'中延遲的毫秒數,解決了問題:) – Wesley 2012-04-21 11:25:06

+0

這段代碼是史詩般的,非常小,像一個魅力!感謝發佈! – deucalion0 2013-03-23 06:46:46

+0

我真的不相信這是一個很好的解決方案。硬編碼值很少。 – katzenhut 2014-05-05 11:45:29

35

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

我不知道這是如何不被接受的最高的答案。它顯然是正確的。反正,從我+1。 – katzenhut 2014-05-05 11:40:57

+1

@ katzenhut因爲在當前的情況下答案是錯誤的。 OP使用的AnimationDrawable甚至不是從動畫派生的。因此,如果使用從Animation類派生的動畫,但對於AnimationDrawable不正確,則此答案是正確的。 AnimationDrawable在其生命週期方面沒有像Animation類那樣的回調。 – AgentKnopf 2015-05-03 10:42:22

+1

@Zainodis - Android中奇怪的命名converntions永遠不會令我驚訝......但你是正確的。感謝您的澄清! – katzenhut 2015-05-04 07:50:47

1

您好另一種選擇是使用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();