javaandroidanimationimageviewanimationdrawable

Pause AnimationDrawable and resume from the same frame


I am trying to animate a set of images using AnimationDrawable. The user should have the ability to pause/resume the animation on a click of a button. I am doing so, using setVisible(boolean visible, boolean restart). Not completely sure if I understand the documentation correctly, but every time pause is pressed, the animation starts from the beginning.

Is there any way to resume the animation from the same frame?

From AnimationDrawable API:

...If restart is false, the drawable will resume from the most recent frame

Just to be clear:

activityAnimation.setVisible(false, false); Should stop the animation.

activityAnimation.setVisible(true, false); Should resume the animation from the same frame (it doesn't).


Here is my code:

The animation start() is called in onWindowFocusChanged.

The animation and the buttons are created in 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);
            }
        }
    });...
}

This is the content of the XML file

<?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>

I have noticed several of these old posts, but non had the answer.

How to reset AnimationDrawable (The other side of this issue)

How do I pause frame animation using AnimationDrawable? [Closed]


Solution

  • Since I needed a timer on the screen as well, the answer in my case was simply to create a runnable replace the ImageView background every second.

    Here is the general idea:

    1. Create the runnable, ImageView and few helpers:

      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. In OnCreate bind the pause and play buttons, fire the timer and set the first ImageView

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_exercise);
      
          // Set the image view
          exImage = (ImageView) findViewById(R.id.image_zero);
          exImage.setBackgroundResource(R.drawable.fe_0);
      
          // Start the timer
          timerHandler.postDelayed(timerRunnable, 0);
      
          // Bind the buttons
          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;
                  //Pause
                  if ((Integer) pp.getTag() == R.drawable.pause) {
                      pauseStartTime = System.currentTimeMillis();
                      timerHandler.removeCallbacks(timerRunnable);
                  } else { // Resume
                      pauseTime += System.currentTimeMillis() - pauseStartTime;
                      timerHandler.postDelayed(timerRunnable, 0);
                  }
              }
          });
      }