slida slida - 6 months ago 37
Android Question

Playing frame animations in a sequence. Android

Ok, somewhat similar questions have been asked, but there is no answer that has made any difference in solving my problem. I've tried Thread.sleep, and also the delayed runnable. Using a Handler, etc.

I want to display a sequence of frame animations(AnimationDrawable) using the same imageview and changing the background animations as needed. The user inputs a series of 5 animations and can then play them back(if my program worked). Once the animations are selected I use a for loop that contains if statements and a switch statement to select that whatever animations were chosen and play them back.

As you might imagine, this doesn't work correctly, as the program whips through the for loop and only the first and last animation actually play. Here is the jist of the code:

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


So as I said, I have tried Thread.sleep(), that doesn't do what I'm looking for. I have tried using the Handler class and putting a delay on the runnable. I have tried this:

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


None of these things do anything at all except add pauses before it does the exact same thing it did before I added this stuff. I have meticulously debugged the code and everything is working correctly. The animations have all been individually tested.

As I said, similar questions have been asked and answered and nothing offered does what I want, which is for the program to wait until one animation is finished before it runs through the for loop again.

I'd like to state again that this is a series of frame animations using AnimationDrawable and the same imageview each time. Thanks in advance!

Answer

All your animations will be started with the same delay, you should increase this delay by multiplying it by i for example. You also can count duration of every animation programmatically and increase delay as you need it.

I just tried to achieve what you want and had no problems, although my example uses 3rd party library, it's not necessary.

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;
    }
}
Comments