Android animation does not repeat

AndroidAnimation

Android Problem Overview


I'm trying to make simple animation that would repeat several times (or infinitely).
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?

Android Solutions


Solution 1 - Android

Update: Back in Sep, 2011 an Android engineer fixed this issue for the most part. The attributes that were ignored in XML now work, with the exception of repeatCount and fillEnabled which are still ignored (on purpose for some reason). This means it still isn't easy to repeat an AnimationSet unfortunately.

For details please see the overview in the updated docs (explains which attributes are ignored, which work, and which are passed onto children). And for a deeper understanding of what fillAfter, fillBefore, and fillEnabled actually do, see the engineer's (Chet Haase) blog post about it here.


Original Answer

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.

Solution 2 - Android

I've found that <set> tag has buggy implementation in class AnimationSet.
It can't deal correctly with repeatCount.
What we can do - is to set repeatCount directly in <scale> tag.

This XML resource is working well:

<?xml version="1.0" encoding="utf-8"?>
<scale
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:interpolator="@android:anim/accelerate_decelerate_interpolator"
	android:duration="200"
	android:fromXScale="1.0"
	android:fromYScale="1.0"
	android:toXScale="1.05"
	android:toYScale="1.05"
	android:pivotX="50%"
	android:pivotY="50%"
	android:repeatMode="reverse"
	android:fillAfter="false"
	android:repeatCount="24"
/>

Unfortunately, this is limited to only one animation at once.
We can not define a sequence of animations this way...

Solution 3 - Android

You should include the attribute

android:repeatCount="infinite"

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

Solution 4 - Android

To get a repeating animation I utilized the animation listener, and called the animation again when it ended. This does a camera reticule focusing like animation with brackets.

Here is the animation layout xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
    android:fromXScale="1.0"
    android:toXScale=".7"
    android:fromYScale="1.0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toYScale=".7"
    android:duration="1000"/>
<scale 
    android:duration="1000"
    android:fromXScale=".7"
    android:toXScale="1.0"
    android:fromYScale=".7"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toYScale="1.0"
    android:startOffset="1000"/>

</set>

Here is the java code

 public void startAnimation() {
	
            View brackets = findViewById(R.id.brackets);
			brackets.setVisibility(View.VISIBLE);
			
			Animation anim = AnimationUtils.loadAnimation(BuzzFinderActivity.this, R.anim.crosshair_focusing);
			anim.setAnimationListener(new AnimationListener() {

				@Override
				public void onAnimationEnd(Animation arg0) {
					Animation anim = AnimationUtils.loadAnimation(BuzzFinderActivity.this, R.anim.crosshair_focusing);
					anim.setAnimationListener(this);
					brackets.startAnimation(anim);
					
				}

				@Override
				public void onAnimationRepeat(Animation arg0) {
					// TODO Auto-generated method stub
					
				}

				@Override
				public void onAnimationStart(Animation arg0) {
					// TODO Auto-generated method stub
					
				}
				
			});
	
			
			brackets.startAnimation(anim);
}

		

Solution 5 - Android

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

http://schemas.android.com/apk/res/android">

  <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"/>

Solution 6 - Android

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.

Solution 7 - Android

I tried to use Daniel's code to show animation exact number of times and had a problem: animation was shown approximatily n / 2 times, when n times expected.

So I have modified Daniel's code:

//...
@Override
public void onAnimationEnd(Animation arg0) {
    mCurrentCount++;
    if (mCurrentCount < REPEAT_COUNT) {  
        Animation anim = AnimationUtils.loadAnimation(BuzzFinderActivity.this, R.anim.crosshair_focusing);
        anim.setAnimationListener(this);
        brackets.post(new Runnable() {
            @Override
            public void run() {
                brackets.startAnimation(anim);
            }
        }  
    } 
}
//... 

Using variant, shown above, animation is shown exectly REPEAT_COUNT times, because View.post() method gives an ability to start new animation after finishing all actions, related with previous animation.

Solution 8 - Android

I solved this problem using android:repeatMode="reverse" before in my project.

<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:repeatMode="reverse"
    android:repeatCount="infinite" />

Solution 9 - Android

you have to add just one line in your xml code that i suggested below .

<scale
    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:repeatCount="infinite" // just add this one line 
    android:fillAfter="false"
    />
</set>

Solution 10 - Android

With android sdk version 4.0.3:

In the given animation elements:

android:repeatCount="-1"

makes it an infinite animation.

Solution 11 - Android

Add the following class to your project:

import android.view.View;
import android.view.animation.Animation;
 
public class AnimationRepeater implements Animation.AnimationListener
{
    private View view;
    private Animation animation;
    private int count;
 
    public AnimationRepeater(View view, Animation animation)
    {
        this.view = view;
        this.animation = animation;
        this.count = -1;
    }
 
    public AnimationRepeater(View view, Animation animation, int count)
    {
        this.view = view;
        this.animation = animation;
        this.count = count;
    }
 
    public void start()
    {
        this.view.startAnimation(this.animation);
        this.animation.setAnimationListener(this);
    }
 
    @Override
    public void onAnimationStart(Animation animation) { }
 
    @Override
    public void onAnimationEnd(Animation animation)
    {
        if (this.count == -1)
            this.view.startAnimation(animation);
        else
        {
            if (count - 1 >= 0)
            {
                this.animation.start();
                count --;
            }
        }
    }
 
    @Override
    public void onAnimationRepeat(Animation animation) { }
}

For infinite loop of your view, do the following:

Animation a = AnimationUtils(Context, R.anim.animation);
new AnimationRepeater(View, a).start();

If you want to repeat the animation for N-times only, do the following:

Animation a = AnimationUtils(Context, R.anim.animation);
new AnimationRepeater(View, a, int N).start();

N stands for number of repetitions.

Solution 12 - Android

I do most of my stuff programmatically and I may be late or inefficient on this one but this but I completed the repeat animationset goal (I a even have 2 alternating animation sets). All this code does is simply fade in one image,pause, then fade out, fade in another image, pause, fade out, and bring back the first one (rinse and repeat). I first defined my Imageviews:

    final ImageView purple = (ImageView)findViewById(R.id.purp);
    final ImageView yellow = (ImageView)findViewById(R.id.yell);
    purple.setVisibility(View.INVISIBLE);
    yellow.setVisibility(View.INVISIBLE);

Then I made two timers, task timers and handlers to deal with when to start and stop each animation:

    Timer p = new Timer();
    TimerTask pu = new TimerTask() {
        public void run() {
                handler1.post(new Runnable() {
                        public void run() 
                        {
                           fadein(purple);
                        }
               });
        }};
        p.schedule(pu, 6000, 12000);

    final Handler handler2 = new Handler();

    Timer y = new Timer();
    TimerTask ye = new TimerTask() {
        public void run() {
                handler2.post(new Runnable() {
                        public void run() 
                        {
                           fadein(yellow);
                        }
               });
        }};

        y.schedule(ye, 0, 12000);

Finally, rather than creating animation sets by adding animations, I just animations listeners to to determine when to start each animation:

public void fadein (final ImageView image)
{
	Animation anim = new AlphaAnimation(0, 1);

	anim.setDuration(2000);
	
	image.startAnimation(anim);
	anim.setAnimationListener(new AnimationListener() {
        public void onAnimationEnd(Animation animation) 
        {
        	image.clearAnimation();
        	image.invalidate();
            pause(image);

        }

		@Override
		public void onAnimationRepeat(Animation animation) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void onAnimationStart(Animation animation) {
			// TODO Auto-generated method stub
			
		}
    });
}    
public void pause (final ImageView image)
{
	Animation anim = new AlphaAnimation(1, 1);

	anim.setDuration(2000);
	
	image.startAnimation(anim);
	anim.setAnimationListener(new AnimationListener() {
        public void onAnimationEnd(Animation animation) 
        {
        	image.clearAnimation();
        	image.invalidate();
            fadeout(image);

        }

		@Override
		public void onAnimationRepeat(Animation animation) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void onAnimationStart(Animation animation) {
			// TODO Auto-generated method stub
			
		}
    });
}     
public void fadeout (final ImageView image)
{
	Animation anim = new AlphaAnimation(1,0);

	anim.setDuration(2000);
	
	image.startAnimation(anim);
	anim.setAnimationListener(new AnimationListener() {
        public void onAnimationEnd(Animation animation) 
        {
        	image.clearAnimation();
        	image.invalidate();
        }

		@Override
		public void onAnimationRepeat(Animation animation) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void onAnimationStart(Animation animation) {
			// TODO Auto-generated method stub
			
		}
    });
}    

The clearanimation and invalidate where just previous attempts and getting this thing to work right. I don't know if they are required or not.

Hope this helps someone.


Ryan

Solution 13 - Android

i got this to go ...i was trying to get a view to rotate in a circle continuously .

previous i was using rotation.setRepeatMode(-1) but that didn't work. switched to setrepeatcount and it works. This is on jelly bean 4.2.2

 ObjectAnimator rotation = ObjectAnimator.ofFloat(myview,
            	          "rotation", 360).setDuration(2000);
            	rotation.setRepeatMode(-1);
          rotation.setRepeatCount(Animation.INFINITE); 
 rotation.start();

Solution 14 - Android

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: http://schemas.android.com/apk/res/android">

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

Solution 15 - Android

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) {
		
	}
	
}

}

Solution 16 - Android

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

Solution 17 - Android

After researching through the answers from internet, I found a solutions which works perfectly for me. (And yes, the repeatCount and repeatMode is extremely buggy when used together with animationSet).

anim_rotate_fade.xml:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:ordering="together" >
    
    <objectAnimator
        android:duration="3000"
        android:propertyName="rotation"
        android:repeatCount="1"
        android:valueTo="360"
        android:valueType="floatType" />
    
    <objectAnimator
        android:duration="3000"
        android:propertyName="alpha"
        android:repeatCount="1"
        android:repeatMode="reverse"
        android:valueFrom="0.0"
        android:valueTo="0.3"
        android:valueType="floatType" />
    
    <objectAnimator
        android:duration="3000"
        android:propertyName="y"
        android:repeatCount="1"
        android:repeatMode="reverse"
        android:valueFrom="380"
        android:valueTo="430"
        android:valueType="floatType" />

</set>

In activity: (Solve it by introducing a slight delay after animation ended).

ImageView starlightImageView = new ImageView(this);
starlightImageView.setImageResource(R.drawable.starlight);
final AnimatorSet animate = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.anim.anim_rotate_fade);
AnimatorListenerAdapter animatorListener = new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
        new Handler().postDelayed(new Runnable() {
            @Override public void run() {
                animate.start();
            }
        }, 1000);
    }
};
animate.setTarget(starlightImageView);
animate.addListener(animatorListener);

There are a lot of classes you would like to research on, but currently I'm using objectAnimator which is highly flexible. I wouldn't recommend to use Animation or AnimationUtils:

  • Animation
  • AnimationUtils
  • Animator
  • AnimatorInflater
  • AnimatorListener
  • AnimatorListenerAdapter

Solution 18 - Android

One need to listen for completion of first animation then re-start the animation in onStopAnimation call back, give a try to this link

Solution 19 - Android

Little tweak to @Danufr answer to save resources from loading again.

    operator = (ImageView) findViewById(R.id.operator_loading);
  final  Animation ani = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.finding_operator);


    ani.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        @Override
        public void onAnimationEnd(Animation animation) {

            operator.startAnimation(ani);

        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
    });

    operator.setAnimation(ani);

Solution 20 - Android

I solved this problem using thread.

Button btn = (Button) findViewById(R.id.buttonpush);
    final TextView textview = (TextView) findViewById(R.id.hello);
    btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            textview.setText("...................");
            final Animation animationtest = AnimationUtils.loadAnimation(MainActivity.this, android.R.anim.slide_in_left);
            animationtest.setDuration(1000);

            final Handler handler = new Handler();
            Runnable runnable = new Runnable() {
                public void run() {
                    handler.postDelayed(this, 1500);
                    textview.startAnimation(animationtest);
                }
            };
            handler.postDelayed(runnable, 500); // start
            handler.removeCallbacks(runnable); //STOP Timer

        }
    });

Solution 21 - Android

it's working fine

 GifDrawable gifDrawable = (GifDrawable) gifImageView.getDrawable();
    gifDrawable.setLoopCount(0);

Solution 22 - Android

None of the above solutions worked in my case. The solution by Danuofr did work for animation set but when I was doing unit testing, my tests used to get stuck in this infinite loop. Finally, specific to my case, I needed to repeat this animation specific number of times. So, I manually added copies of my animation in anim_rot.xml in a cascaded manner adding the offset value. I know it's bad and won't work for many but it was the only workaround for my case.

anim_rot.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <rotate
        android:duration="2000"
        android:fromDegrees="20"
        android:pivotX="29%"
        android:pivotY="50%"
        android:toDegrees="-20" />
    <rotate
        android:duration="2000"
        android:fromDegrees="-20"
        android:pivotX="29%"
        android:pivotY="53%"
        android:startOffset="2000"
        android:toDegrees="20" />
    <rotate
        android:startOffset="4000"
        android:duration="2000"
        android:fromDegrees="20"
        android:pivotX="29%"
        android:pivotY="56%"
        android:toDegrees="-20" />
    <rotate
        android:duration="2000"
        android:fromDegrees="-20"
        android:pivotX="29%"
        android:pivotY="59%"
        android:startOffset="6000"
        android:toDegrees="20" />
    <rotate
        android:startOffset="8000"
        android:duration="2000"
        android:fromDegrees="20"
        android:pivotX="29%"
        android:pivotY="62%"
        android:toDegrees="-20" />
    <rotate
        android:duration="2000"
        android:fromDegrees="-20"
        android:pivotX="29%"
        android:pivotY="65%"
        android:startOffset="10000"
        android:toDegrees="20" />
</set>

I did this to repeat the animation 3 times. You can add more copies to repeat it specific times by adding offset values.

Solution 23 - Android

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPavel ChernovView Question on Stackoverflow
Solution 1 - AndroidTony ChanView Answer on Stackoverflow
Solution 2 - AndroidPavel ChernovView Answer on Stackoverflow
Solution 3 - AndroidMacumbaomuerteView Answer on Stackoverflow
Solution 4 - AndroidDanuofrView Answer on Stackoverflow
Solution 5 - AndroidabhilashView Answer on Stackoverflow
Solution 6 - AndroidInformaticsView Answer on Stackoverflow
Solution 7 - AndroidDenisView Answer on Stackoverflow
Solution 8 - AndroidHuseyinView Answer on Stackoverflow
Solution 9 - AndroidMitesh SawantView Answer on Stackoverflow
Solution 10 - AndroidKurt JunghannsView Answer on Stackoverflow
Solution 11 - AndroiddomiView Answer on Stackoverflow
Solution 12 - AndroidtestingtesterView Answer on Stackoverflow
Solution 13 - Androidj2emanueView Answer on Stackoverflow
Solution 14 - AndroidJordiView Answer on Stackoverflow
Solution 15 - Androidxander_blrView Answer on Stackoverflow
Solution 16 - AndroidnewbycaView Answer on Stackoverflow
Solution 17 - Androidmorph85View Answer on Stackoverflow
Solution 18 - AndroidRavi K. SharmaView Answer on Stackoverflow
Solution 19 - AndroidMr CoderView Answer on Stackoverflow
Solution 20 - Androidnikeru8View Answer on Stackoverflow
Solution 21 - AndroidBHAVIKView Answer on Stackoverflow
Solution 22 - AndroidSachin AggarwalView Answer on Stackoverflow
Solution 23 - AndroidcarefacerzView Answer on Stackoverflow