Repeat AnimatorSet

2020-06-08 06:42发布

问题:

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?

回答1:

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.



回答2:

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.



回答3:

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


回答4:

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
}


回答5:

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.



回答6:

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();


回答7:

How about this?

@Override
public void onAnimationEnd(Animator animation) {
    if (!mCanceled) {
        animation.reset();  //<- added.
        animation.start();
    }
}