4

I want to setup infinite color animation, that would change color from random start color to random end color, then from that random end color to next random end color and etc. I tried to setup this value animator:

ValueAnimator valueAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), randomColorStart, randomColorEnd);

And then tried to update randomColorStart and randomColorEnd on onAnimationRepeat() method, but updated values do not affect animation. How could I accomplish this?

wilkas
  • 1,161
  • 1
  • 12
  • 34

2 Answers2

2

I don't know whether this solution is best. But, it works!

In a nutshell, I created ValueAnimator and set its repeat mode to INFINITE. Then, I implemented Animator.AnimatorListener to override onAnimationRepeat, which is called when duration time ends. And then, inside onAnimationRepeat I am generating next random color.

    int nextColor; // class-scope variable
    int startColor; // class-scope variable

    final Random rnd = new Random();
    final float[] hsv = new float[3];
    final float[] from = new float[3];
    final float[] to = new float[3];

    //generate random initial color and next color
    startColor = Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
    nextColor = Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));

    // to get nicer smooth transition I'm using HSV 
    Color.colorToHSV(startColor, from);
    Color.colorToHSV(nextColor, to);

    final ValueAnimator anim = ValueAnimator.ofInt(startColor, nextColor);
    // animate from the current color to the next color;

    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            hsv[0] = from[0] + (to[0] - from[0]) * animation.getAnimatedFraction();
            hsv[1] = from[1] + (to[1] - from[1]) * animation.getAnimatedFraction();
            hsv[2] = from[2] + (to[2] - from[2]) * animation.getAnimatedFraction();

            view.setBackgroundColor(Color.HSVToColor(hsv));
        }
    });


    anim.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {

        }

        @Override
        public void onAnimationEnd(Animator animation) {

        }

        @Override
        public void onAnimationCancel(Animator animation) {

        }

        @Override
        public void onAnimationRepeat(Animator animation) {
            // generate next random color
            startColor = Color.HSVToColor(to);
            nextColor = Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));

            Color.colorToHSV(startColor, from);
            Color.colorToHSV(nextColor, to);
        }
    });

    anim.setDuration(4000); // duration to change colors
    anim.setRepeatCount(ValueAnimator.INFINITE);
    anim.start();
SpiralDev
  • 7,011
  • 5
  • 28
  • 42
  • I'll review this over the weekend. I've tried a similar approach with no luck, maybe some error caused this. – wilkas Nov 04 '16 at 14:28
  • this one should work. I tested it myself. Let me know if u get error – SpiralDev Nov 04 '16 at 14:40
  • I must have left an error somewhere, as my animation started flickering colors after first normal iteration. By the way, its better to use `AnimatorListenerAdapter()` instead of `AnimatorListener()` to shorten the code. Can you tell me why HSV makes smoother transition than `ValueAnimator.ofObject(new ArgbEvaluator(), randomColorStart, randomColorEnd);`? – wilkas Nov 05 '16 at 05:35
  • 1
    Refer [here](https://www.kirupa.com/design/little_about_color_hsv_rgb.htm) and [here](http://stackoverflow.com/a/24641977/5985958) – SpiralDev Nov 05 '16 at 08:55
0

I think accepted answer is a little hackish

There is api in most of Animator subclasses, which can help up to change start/end value while animation is running (or onRepeat) enter image description here

Lets take ValueAnimator for example

    ValueAnimator.ofFloat(
        1f,
        3f
    ).apply {
        repeatCount = 2
        repeatMode = RESTART
        addUpdateListener {
            textView.scaleX = it.animatedValue
            textView.scaleY = it.animatedValue
        }
        doOnRepeat {
            // lets change start and end valeus
            (it as ValueAnimator).setFloatValues(1f, 5f)
        }
        start()
    }

We can cast animator to animator we need (ValueAnimator, ObjectAnimator, etc) and set start and end value (which can be float, object, or any other)

Efimov Aleksandr
  • 165
  • 2
  • 12