Android animation does not repeat
Solution 1:
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 AnimationSet
s):
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:
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:
You should include the attribute
android:repeatCount="infinite"
But in your "scale" animation not in "set"
Solution 4:
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);
}