Is there a simple way to repeat a Android AnimatorSet
(infinite)? Can I set a AnimationListener
and restart the AnimatorSet
by calling start()
again?
My AnimatorSet
contains two animations that are played sequentially.
So if I set the repeat mode of both single animation to repeat, than the first will be repeated while the second runs, right?
set it's child object animators' repeat mode and count;
objectAnimator.setRepeatCount(ObjectAnimator.INFINITE);
objectAnimator.setRepeatMode(ObjectAnimator.RESTART/REVERSE...);
This won't be able to be stopped, or cancelled, however, due to yet another bug.
clearly, I'm not a fan of the myriad ways in which you can animate things in Android, and have them all fail you in one way or the other. Hope this helps somebody else.
There is an answer for the first two questions
Is there a simple way to repeat a Android AnimatorSet (infinite)? Can I set a AnimationListener and restart the animatorSet by calling start() again?
Yes, there is:
mAnimationSet.addListener(new AnimatorListenerAdapter() {
private boolean mCanceled;
@Override
public void onAnimationStart(Animator animation) {
mCanceled = false;
}
@Override
public void onAnimationCancel(Animator animation) {
mCanceled = true;
}
@Override
public void onAnimationEnd(Animator animation) {
if (!mCanceled) {
animation.start();
}
}
});
mAnimationSet.start();
The answer for the third question, is no. The first animation will be repeated and after all repetitions the succeeding animation will be started.
No, you can't repeat AnimatorSet, you can only repeat of a single ObjectAnimator/ ValueAnimator
But you can use PropertyValuesHolder, so that you can make an ObjectAnimator from a set of PropertyValuesHolder
here's example
val translateY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, -100f, 100f)
val alpha = PropertyValuesHolder.ofFloat(View.ALPHA, 0.3f, 0.7f)
val scaleX = PropertyValuesHolder.ofFloat(View.SCALE_X, 0.8f, 1.2f)
val scaleY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 0.8f, 1.2f)
// and more
ObjectAnimator.ofPropertyValuesHolder(myView, translateY, alpha, scaleX, scaleY).apply {
interpolator = AccelerateDecelerateInterpolator()
// duration of each animation
duration = 500L
// repeat infinite count (you can put n times)
repeatCount = ValueAnimator.INFINITE
// reverse animation after finish
repeatMode = ValueAnimator.REVERSE
// start animation
start()
}
Set Infinite repeat count and restart / reverse repeat mode to all child animations
animatorSet.childAnimations.forEach {
val animator = it as ObjectAnimator
animator.repeatCount = ObjectAnimator.INFINITE
animator.repeatMode = ObjectAnimator.RESTART / REVERSE
}
Out of my head - animation framework is source of pain, especially if you want to support 2.x. I usually had problems with sets trying to do anythig more complexKeep track of with AnimationListener
kind-of "player". I keep track on which animation I play (like int
etc) and then on onAnimationEnd
I start another that should be in sequence. That way I can easily "script" my sequence, and do not bother broken framework.
So, none of the above options are appropriate.
If you use:
@Override
public void onAnimationEnd(Animator animation) {
if (!mCanceled) {
animation.start();
}
}
you will end up getting stackOverFlow exception sometimes.
The best thing is to do something like:
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true && getActivity() != null) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
set3.start();
}
});
SystemClock.sleep(1200);
}
}
});
t.start();
How about this?
@Override
public void onAnimationEnd(Animator animation) {
if (!mCanceled) {
animation.reset(); //<- added.
animation.start();
}
}