android: Animate color change from color to color

Solution 1:

Combining @zed's and @Phil's answer gives a nice smooth transition using the ValueAnimator.

final float[] from = new float[3],
              to =   new float[3];

Color.colorToHSV(Color.parseColor("#FFFFFFFF"), from);   // from white
Color.colorToHSV(Color.parseColor("#FFFF0000"), to);     // to red

ValueAnimator anim = ValueAnimator.ofFloat(0, 1);   // animate from 0 to 1
anim.setDuration(300);                              // for 300 ms

final float[] hsv  = new float[3];                  // transition color
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
    @Override public void onAnimationUpdate(ValueAnimator animation) {
        // Transition along each axis of HSV (hue, saturation, value)
        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.start();                                        

The HSV will give a nicer transition than Androids default color space because HSV describes colors in cylindrical coordinates that nicely separate the color's properties and allow a smooth transition across a single axis. You can see from the image below that traveling along the H, S, or V directions gives a nice continuous transition between colors.

enter image description here

Solution 2:

You can simply use ArgbEvaluator which is available since API 11 (Honeycomb):

ValueAnimator anim = new ValueAnimator();
anim.setIntValues(color1, color2);
anim.setEvaluator(new ArgbEvaluator());
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator valueAnimator) {
        view.setBackgroundColor((Integer)valueAnimator.getAnimatedValue());
    }
});

anim.setDuration(300);
anim.start();

Even better, beginning with API 21 (Lollipop 5.0) you can replace the first 3 lines in the code above with one:

ValueAnimator anim = ValueAnimator.ofArgb(color1, color2)

Solution 3:

You can use a ValueAnimator:

//animate from your current color to red
ValueAnimator anim = ValueAnimator.ofInt(view.getBackgroundColor(), Color.parseColor("#FF0000"));
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        view.setBackgroundColor(animation.getAnimatedValue());
    }
});

anim.start();

You can also set duration or other parameters before calling anim.start(). For example:

anim.setDuration(400);

will set the animation duration to 400ms.


Finally, note that ValueAnimator is available starting in Honeycomb, so if you are supporting older SDKs, you can use NineOldAndroids.

Solution 4:

best way use blendARGB in ColorUtils.

esay and minimum line code.

view.setBackgroundColor(ColorUtils.blendARGB(Color.parseColor("#FFFFFF"), Color.parseColor("#CCCCCC"), fraction));

Solution 5:

The other answers gave me a weird effect when transitioning very different colors. From yellow to gray it would reach green at some point during the animation.

What worked best for me was the following snippet. This created a really smooth transition with no weird colors appearing in-between.

private void changeViewColor(View view) {
    // Load initial and final colors.
    final int initialColor = getResources().getColor(R.color.some_color);
    final int finalColor = getResources().getColor(R.color.another_color);

    ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            // Use animation position to blend colors.
            float position = animation.getAnimatedFraction();
            int blended = blendColors(initialColor, finalColor, position);

            // Apply blended color to the view.
            view.setBackgroundColor(blended);
        }
    });

    anim.setDuration(500).start();
}

private int blendColors(int from, int to, float ratio) {
    final float inverseRatio = 1f - ratio;

    final float r = Color.red(to) * ratio + Color.red(from) * inverseRatio;
    final float g = Color.green(to) * ratio + Color.green(from) * inverseRatio;
    final float b = Color.blue(to) * ratio + Color.blue(from) * inverseRatio;

    return Color.rgb((int) r, (int) g, (int) b);
}