web-dev-qa-db-ja.com

Androidアニメーション:終了するまで待ちますか?

Android ImageViewでアニメーションが終了するまで待機してから、プログラムの実行を続行します。これを行う適切な方法は何ですか?

  • (このコンテキストでは、「終了」とは、すべてのフレームを1回だけ実行し、最後のフレームで停止することを意味します。このアニメーションがAndroid:oneshot = "true"アニメーションになるかどうかは不明です。が、連続的にではなく断続的に実行されます)

研究/推測:

A.心の中で私の質問は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>

私の質問への答えではありませんが、望ましい効果を達成するための1つの可能な方法は、次のようなことをして、さらなるコードの実行を遅らせることです:

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呼び出しでアニメーションを直接実行しました。最後の反復では、スレッド化されたサーフェスビューを使用してアニメーションを実行しています。この最後の方法は断然最速かつ最高です(この投稿で質問された以外の理由で)。私はそれが誰かを助けることを願っています。

30
tjb

提案する

  • 「アニメーション」ライフタイムをカプセル化するオブジェクトを作成します
  • オブジェクトには、スレッドOR Timer
  • 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();
    }
}
_

単一のスレッドまたはThreadPoolExecutorScheduledThreadPoolExecutorを使用し、アニメーションの各フレームをCallableとしてキャプチャすることもできます。 Callablesのシーケンスを送信し、invokeAll()またはCompletionServiceを使用して、アニメーションが完了するまで関心のあるスレッドをブロックします。

9
andersoj

最も簡単な方法は、(遅延した)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スレッドをブロックしようとしないでください(決して、決して、決して!)。そうすると、電話がフリーズし、とにかくアニメーションが表示されなくなります。しばらく待つ必要がある場合は、別のスレッドを使用してください。

50
netzpurist

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);
42
helder.vasc

こんにちは別の選択肢は 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();
2
Pranaysharma