【问题标题】:Playing frame animations in a sequence. Android按顺序播放帧动画。安卓
【发布时间】:2015-09-08 00:07:49
【问题描述】:

好的,有人问了一些类似的问题,但没有任何答案对解决我的问题有任何影响。我试过 Thread.sleep,还有延迟的可运行。使用处理程序等。

我想使用相同的图像视图显示一系列帧动画(AnimationDrawable),并根据需要更改背景动画。用户输入一系列 5 个动画,然后可以播放它们(如果我的程序有效)。选择动画后,我使用包含 if 语句和 switch 语句的 for 循环来选择选择的任何动画并播放它们。

正如您可能想象的那样,这不能正常工作,因为程序在 for 循环中快速运行,并且只有第一个和最后一个动画实际播放。这是代码的jist:

for(i=0;i<5;i++){
    if(conditions){
        view.setBackground(chosenAnimation);
        ((AnimationDrawable)view.getBackground().start();
    }
}

正如我所说,我已经尝试过 Thread.sleep(),但它并没有达到我想要的效果。我尝试使用 Handler 类并延迟可运行对象。我试过这个:

view.postDelayed(new Runnable() {
    @Override 
    public void run() {
        //works the same without this line
        ((AnimationDrawable)view.getBackground()).stop();
        ((AnimationDrawable)view.getBackground()).start();
    }
}, 1000);

这些东西根本没有做任何事情,除了在它做与我添加这些东西之前完全相同的事情之前添加暂停。我已经仔细调试了代码,一切正常。动画都经过单独测试。

正如我所说,已经提出并回答了类似的问题,但没有提供任何我想要的东西,即程序要等到一个动画完成后再再次运行 for 循环。

我想再次声明,这是一系列使用 AnimationDrawable 的帧动画,每次都使用相同的 imageview。提前致谢!

【问题讨论】:

    标签: java android animation


    【解决方案1】:

    您的所有动画都将以相同的延迟开始,例如,您应该通过将其乘以 i 来增加此延迟。您还可以以编程方式计算每个动画的持续时间,并根据需要增加延迟。

    我只是尝试实现您想要的并且没有任何问题,虽然我的示例使用了 3rd 方库,但这不是必需的。

    package com.example.masktest.app;
    
    import android.animation.Animator;
    import android.graphics.drawable.AnimationDrawable;
    import android.os.Bundle;
    import android.support.v4.content.ContextCompat;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.widget.ImageView;
    
    import java.lang.ref.SoftReference;
    import java.lang.ref.WeakReference;
    import java.util.concurrent.atomic.AtomicReference;
    
    import static com.dtx12.android_animations_actions.actions.Actions.*;
    
    
    public class MainActivity extends AppCompatActivity {
    
        ImageView imageView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            imageView = (ImageView) findViewById(R.id.imageView);
            findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    playAnimation();
                }
            });
        }
    
        private void playAnimation() {
            final AnimationDrawable firstDrawable = (AnimationDrawable) ContextCompat.getDrawable(MainActivity.this, R.anim.anim_android);
            final AnimationDrawable secondDrawable = (AnimationDrawable) ContextCompat.getDrawable(MainActivity.this, R.anim.anim_android_2);
            final AtomicReference<Integer> cpt = new AtomicReference<>(0);
            Animator sequence = repeat(6, sequence(run(new Runnable() {
                @Override
                public void run() {
                    if (imageView.getDrawable() instanceof AnimationDrawable) {
                        ((AnimationDrawable) imageView.getDrawable()).stop();
                    }
                    imageView.setImageDrawable(cpt.get() % 2 == 0 ? secondDrawable : firstDrawable);
                    ((AnimationDrawable) imageView.getDrawable()).start();
                    cpt.set(cpt.get() + 1);
                }
            }), delay(countAnimationDuration(secondDrawable))));
            play(sequence, imageView);
        }
    
        private float countAnimationDuration(AnimationDrawable drawable) {
            int duration = 0;
            for (int i = 0; i < drawable.getNumberOfFrames(); i++) {
                duration += drawable.getDuration(i);
            }
            return duration / 1000f;
        }
    }
    

    【讨论】:

    • 感谢您的回答。问题是这些延迟似乎对结果没有任何影响,在 for 循环完成之前没有任何动画运行。我尝试的最新方法是更新视图并使用处理程序在单独的线程中启动动画,然后在 for 循环的末尾添加 Thread.sleep()。结果是它慢慢地跑过for循环,然后当for循环结束时,它鞭打其他线程,只播放最后一个动画。我认为除了我正在做的事情之外,还有更多的事情要做。第一次尝试使用线程。
    • 我只是想达到你想要的,没有任何问题。我已经用示例更新了我的答案。
    • 谢谢!我不熟悉其中一些课程,但我会做一些研究。看起来你的设置比我的好很多。我会努力的,看看能不能搞定。
    • 所以,我想通了!你确切地告诉我我做错了什么,但直到我开始意识到我的代码实际上在做什么,我才明白。在您的示例中,我无法弄清楚您对 Animator 类做了什么,但我现在已经知道如何去做了。谢谢!
    【解决方案2】:

    您可以简单地使用 for 循环,并且不需要 3rd 方库。

    假设您有一个想要动态添加这些按钮的 LinearLayout(或任何视图组)。你可以这样做:

    for (int i = 0; i < buttons.size(); i++) {
       Button button = new Button(context); 
       new Handler().postDelayed(new Runnable() {
           @Override 
           public void run() { 
              linearLayout.addView(button);
              animateButton(button);
           } 
       }, BUTTON_DELAY_DURATION * i);
    } 
    

    【讨论】:

      【解决方案3】:

      感谢 dtx12 的帮助,我意识到了我的问题,我想我会在这里留下一些代码,因为我不够好,无法完全理解他们的示例。

      我不太明白我在做什么创建新线程,事实证明我只是在创建 5 个线程,所有线程都同时关闭,正如 dtx12 解释的那样,我最终理解了。所以这里有一个基本的方法:

      public void playAnimation(){
          // in dtx12's answer they demonstrate how to get the
          // exact duration of any give animation using 
         //getNumberOfFrames() and getDuration() methods of 
         // AnimationDrawable but I am just hardcoding it for simplicity
      
          int duration=2000;
         // This is to keep track of the animations which are in an array, I use this variable in run()
           order=1;
      
                        for(int i=0;i<5;i++){
        //play the first animation
      
                            if(i==0){
                                view.setBackground(animation[0]);
                                  animation[i].stop();
                                  animation[i].start();
      
                            }
                            else{
      //Now set up the next animation to play after 2000ms, the next  after 4000ms, etc.
      //You are supposed to use a handler if you want to change the view in the main thread.
      //it is very easy: Handler handler=new Handler():
      
                                handler.postDelayed(new Runnable(){
      
                                  @Override
                                  public void run() {
      
                                       view.setBackground(animation[order]);
                                      animation[order].stop();
                                      animation[order].start();
                                      order++;
      
      
                                  }
      
                                }, duration);
             //dtx12 suggestion of multiplying by i is probably smarter                 
                                duration+=2000;
      
                            }
      
                        }
      
      
      
                      }
      

      所以你有它。不是最优雅的编码展示,但它完成了基本工作。您不能在 run() 方法中使用 'i',因为它是一个匿名内部类,如果将 'i' 的值分配给循环中的另一个变量,它将是 '4',到其他线程执行。所以,我只是在 run 内部做了一些计数,以确保一切都按顺序触发。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多