暂停AnimationDrawable并从相同的帧恢复

3
我正在尝试使用AnimationDrawable动画一组图像。用户应该能够在点击按钮时暂停/恢复动画。我使用setVisible(boolean visible,boolean restart)来实现这一点。不完全确定我是否正确理解了文档,但每次按下暂停按钮时,动画都会从头开始。
有没有办法从相同的帧恢复动画呢?
AnimationDrawable API
如果restart为false,则可绘制项将从最近的帧恢复
仅为清晰起见: activityAnimation.setVisible(false,false);应该停止动画。 activityAnimation.setVisible(true,false);应该从相同的帧恢复动画(但它没有)。

这是我的代码:

动画start()onWindowFocusChanged中被调用。

动画和按钮都是在onCreate中创建的:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_content);

    ImageView activityImage = (ImageView) findViewById(R.id.activity_image);
    activityImage.setBackgroundResource(R.drawable.anim);
    activityAnimation = (AnimationDrawable) activityImage.getBackground();

    ....
    b.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            ImageButton b = (ImageButton) v;
            if ((Integer)b.getTag() == R.drawable.pause) {
                b.setImageResource(R.drawable.play);
                b.setTag(R.drawable.play);
                activityAnimation.setVisible(false, false);
            } else {
                b.setImageResource(R.drawable.pause);
                b.setTag(R.drawable.pause);
                activityAnimation.setVisible(true, false);
            }
        }
    });...
}

这是 XML 文件的内容

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">

    <item android:drawable="@drawable/one" android:duration="1000" />
    <item android:drawable="@drawable/two" android:duration="1000" />
    <item android:drawable="@drawable/three" android:duration="1000" />
    <item android:drawable="@drawable/four" android:duration="1000" />

</animation-list>

我注意到有几篇旧帖子,但都没有答案。 如何重置AnimationDrawable(此问题的另一面) 如何暂停使用AnimationDrawable的帧动画?[已关闭]

你在哪个版本的Android上看到这种行为? - user
为了模拟,我使用Genymotion(Galaxy s5 - 4.4.4 - API19)。Android Studio 2.2.3,最新的SDK。 - Idan
尝试使用更高的API级别设备(Lollipop及以上版本),并查看行为是否仍然存在。我已经查看了AnimationDrawable的代码,似乎在较低版本上它只是重新启动动画,而较高版本则有一些逻辑来从当前帧开始进行动画。 - user
检查API 23,同样的问题。 - Idan
我亲眼看到了。就像我之前说的,在低版本中,该代码只是重置动画,而在高版本中,它尝试恢复动画(但显然失败了)。所以,这可能是代码中的错误,或者文档是误导性的。作为一种替代方案,您可以通过将动画可绘制对象加载到数组中,然后使用Handler发布Runnable来更新ImageView的背景,并从上述数组中获取可绘制对象来复制动画效果(这基本上是AnimationDrawable正在做的)。 - user
2个回答

1

要暂停和恢复AnimationDrawable,只需自定义它并处理一个变量即可。

class CustomAnimationDrawable1() : AnimationDrawable() {

private var finished = false
private var animationFinishListener: AnimationFinishListener? = null
private var isPause = false
private var currentFrame = 0

fun setFinishListener(animationFinishListener: AnimationFinishListener?) {
    this.animationFinishListener = animationFinishListener
}

interface AnimationFinishListener {
    fun onAnimationFinished()
}


override fun selectDrawable(index: Int): Boolean {
    val ret = if (isPause) {
        super.selectDrawable(currentFrame)
    } else {
        super.selectDrawable(index)
    }

    if (!isPause) {
        currentFrame = index
        if (index == numberOfFrames - 1) {
            if (!finished && ret && !isOneShot) {
                finished = true
                if (animationFinishListener != null) animationFinishListener!!.onAnimationFinished()
            }
        }
    }
    return ret
}

fun pause() {
    isPause = true
}

fun resume() {
    isPause = false
}

}


0

由于我需要在屏幕上显示一个计时器,所以在我的情况下,答案就是创建一个可运行的替换ImageView背景每秒钟。

这是一般的想法:

  1. 创建可运行的ImageView和几个帮助程序:

    ImageView exImage = null;
    
    long startTime = 0;
    long pauseTime = 0;
    long pauseStartTime = 0;
    
    List<Integer> animList = new ArrayList<>();
    int animIt = 0;        
    
    Handler timerHandler = new Handler();
    Runnable timerRunnable = new Runnable() {
        @Override
        public void run() {
    
            long millis = System.currentTimeMillis() - startTime - pauseTime;
            double dSecs = (double) (millis / 100);
            int pace = 10;
    
            if (dSecs % pace == 0.0 && !animList.isEmpty()) {
                animIt = (animIt == animList.size() - 1) ? 0 : animIt + 1;
                exImage.setBackgroundResource(animList.get(animIt));
            }
            timerHandler.postDelayed(this, 100);
        }
    };
    
  2. OnCreate中绑定暂停和播放按钮,启动计时器并设置第一个ImageView

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_exercise);
    
        // 设置图像视图
        exImage = (ImageView) findViewById(R.id.image_zero);
        exImage.setBackgroundResource(R.drawable.fe_0);
    
        // 启动计时器
        timerHandler.postDelayed(timerRunnable, 0);
    
        // 绑定按钮
        ImageButton pp = (ImageButton) findViewById(R.id.button_play_pause_toggle);
        pp.setImageResource(R.drawable.pause);
        pp.setTag(R.drawable.pause);
    
        pp.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ImageButton pp = (ImageButton) v;
                //暂停
                if ((Integer) pp.getTag() == R.drawable.pause) {
                    pauseStartTime = System.currentTimeMillis();
                    timerHandler.removeCallbacks(timerRunnable);
                } else { // 恢复
                    pauseTime += System.currentTimeMillis() - pauseStartTime;
                    timerHandler.postDelayed(timerRunnable, 0);
                }
            }
        });
    }
    

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