Tuesday, April 10, 2012

Android animation does not repeat


I'm trying to make simple animation that is repeated several times (or infinite).





It seems that android:repeatCount does not work!

Here is my animation resource from /res/anim/first_animation.xml :




<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false"
android:repeatCount="infinite"
>
<scale
android:interpolator="@android:anim/decelerate_interpolator"
android:duration="500"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:toXScale="1.2"
android:toYScale="1.2"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="false" />
<scale
android:interpolator="@android:anim/accelerate_interpolator"
android:startOffset="500"
android:duration="500"
android:fromXScale="1.2"
android:fromYScale="1.2"
android:toXScale="1.0"
android:toYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="false" />
</set>



First it should scale image from 1.0 to 1.2 size in 500 ms.

And then scale it back to 1.0 in 500 ms.

Here is how I'm using it:




Animation firstAnimation = AnimationUtils.loadAnimation(this, R.anim.first_animation);
imgView.startAnimation(firstAnimation);



It makes one cycle and then finishes.

It scales up, then scales down ans then stops.



How can I make this work as intended?


Source: Tips4all

9 comments:

  1. To expand upon answers by Pavel and others: it is true that the <set> tag is ridiculously buggy. It can't deal correctly with repeatCount and a number of other attributes.

    I spent a few hours figuring out what it can and can't deal with and have submitted a bug report/issue here: Issue 17662

    In summary (this concerns AnimationSets):


    setRepeatCount() / android:repeatCount


    This attribute (as well as repeatMode) does not work in code or XML. This makes repeating an entire set of animations difficult.


    setDuration() / android:duration


    Setting this on an AnimationSet in code WORKS (overrides all durations of children animations), but not when included in the tag in XML


    setFillAfter() / android:fillAfter


    This works in both code and XML for the tag. Strangely I have gotten it to also work without the need to set fillEnabled to true.


    setFillBefore() / android:fillBefore


    Seems to have no effect/ignored in both code and XML


    setFillEnabled() / android:fillEnabled


    Seems to have no effect/ignored in both code and XML. I can still get fillAfter to work even without including fillEnabled or setting fillEnabled to false.


    setStartOffset() / android:startOffset


    This works only in code and not XML.

    ReplyDelete
  2. You should include the attribute

    android:repeatCount="infinite"


    But in your "scale" animation not in "set"

    ReplyDelete
  3. Try to add the code to a looping thread or a while/for statement

    ReplyDelete
  4. exactly, you have to put both RepeatCount and RepeatMode to infinite

    ReplyDelete
  5. I was also facing the same problem..
    i included android:repeatCount="infinite" in XMl file..now its working fine...




    <translate
    android:fromXDelta="0"
    android:toXDelta="80"
    android:duration="1000"
    android:repeatCount="infinite"
    android:repeatMode="reverse"
    android:pivotX="50%"
    android:pivotY="50%"
    android:fillAfter="true"/>

    ReplyDelete
  6. I've faced the same problem, but didn't want to do any timing things in Java because of the point that the UI thread may be very busy sometimes.
    The INFINITE flag doesn't work for the set tag. So I resolved the issue with a little piece of code:

    mAnimation = (AnimationSet) AnimationUtils.loadAnimation(myContext, R.anim.blink);
    mIcon.startAnimation(mAnimation);
    mAnimation.setAnimationListener(new AnimationListener() {
    public void onAnimationStart(Animation animation) {}
    public void onAnimationRepeat(Animation animation) {}
    public void onAnimationEnd(Animation animation) {
    mIcon.startAnimation(mAnimation);
    }
    });


    with the following XML:



    <alpha
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromAlpha="0.0"
    android:toAlpha="1.0" />

    <alpha
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromAlpha="0.9"
    android:startOffset="1000"
    android:toAlpha="0.0" />




    Where mIcon is an ImageView from my layout.

    ReplyDelete
  7. I've solved this problem. This is my version of the fix:

    public class HelloAndroidActivity extends Activity {
    private static String TAG = "animTest";
    private Animation scaleAnimation;
    private int currentCover = 0;
    private List<ImageView> imageViews = new ArrayList<ImageView>(3);
    private Button btn;
    private ImageView img;

    /**
    * Called when the activity is first created.
    * @param savedInstanceState If the activity is being re-initialized after
    * previously being shut down then this Bundle contains the data it most
    * recently supplied in onSaveInstanceState(Bundle). <b>Note: Otherwise it is null.</b>
    */
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.i(TAG, "onCreate");
    setContentView(R.layout.test);

    img = (ImageView)findViewById(R.id.testpict);
    imageViews.add(img);
    img = (ImageView)findViewById(R.id.testpictTwo);
    imageViews.add(img);
    img = (ImageView)findViewById(R.id.testpict3);
    imageViews.add(img);

    scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.photo_scale);
    scaleAnimation.setAnimationListener(new CyclicAnimationListener());

    btn = (Button)findViewById(R.id.startBtn);
    btn.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View v) {
    imageViews.get(0).startAnimation(scaleAnimation);
    }
    });



    }

    private class CyclicAnimationListener implements AnimationListener{

    @Override
    public void onAnimationEnd(Animation animation) {
    currentCover += 1;
    if(currentCover >= imageViews.size()){
    currentCover = 0;
    }
    img = imageViews.get(currentCover);
    scaleAnimation = AnimationUtils.loadAnimation(HelloAndroidActivity.this, R.anim.photo_scale);
    scaleAnimation.setAnimationListener(new CyclicAnimationListener());
    img.startAnimation(scaleAnimation);
    }

    @Override
    public void onAnimationRepeat(Animation animation) {
    Log.d("Animation", "Repeat");
    }

    @Override
    public void onAnimationStart(Animation animation) {

    }

    }

    }

    ReplyDelete
  8. i just came across this issue while working on a backwards compatible app. so frustrating! i ended up coding a nice workaround class that can be called from onCreate and will kickoff any animation resource into an indefinite loop.

    the class, AnimationLooper, is available here:
    https://gist.github.com/2018678

    ReplyDelete
  9. you can try this code.
    In your code just add,

    firstAnimation.setRepeatCount(5);


    This will repeat the animation for a definite time

    firstAnimation.setRepeatCount(Animation.INFINITE);
    firstAnimation.setRepeatMode(Animation.INFINITE);


    This will repeat the animation indefinitely.

    ReplyDelete