按顺序播放帧动画。Android

3

好的,类似的问题已经被问过了,但是没有任何答案能够解决我的问题。我尝试使用Thread.sleep和延迟runnable。使用Handler等。

我想要使用相同的ImageView显示一系列帧动画(AnimationDrawable),并根据需要更改背景动画。用户输入一系列5个动画,然后可以播放它们(如果我的程序正常工作)。一旦选择了动画,我就使用包含if语句和switch语句的for循环来选择所选的动画并播放它们。

正如你所想象的那样,这不起作用,因为程序通过for循环,并且只有第一个和最后一个动画实际播放。以下是代码的主要内容:

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进行的一系列帧动画。提前感谢您的帮助!

3个回答

2

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

我刚尝试了一下您想要的内容,并没有遇到任何问题,尽管我的示例使用了第三方库,但这不是必需的。

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循环完成时,它会快速通过其他线程,并且只播放最后一个动画。我认为需要做更多的事情。这是我第一次尝试使用线程。 - slida
我刚刚尝试了一下你想要的,没有遇到任何问题。我已经更新了我的答案,并提供了示例。 - dtx12
谢谢!我对其中一些类不太熟悉,但我会进行一些研究。看起来你的设置比我的好很多。我会努力改进并尝试让它运行起来。 - slida
所以,我弄清楚了!你告诉我我做错了什么,但是直到我开始意识到我的代码实际上在做什么,我才明白。我无法弄清楚你在示例中使用Animator类的操作,但现在我已经搞清楚了如何做。谢谢! - slida

1
你可以简单地使用for循环,而不需要第三方库。
假设你有一个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);
} 

0

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

我并没有完全理解我正在创建新线程时在做什么,结果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内部进行了一些计数,以确保一切按顺序触发。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接