android color between two colors, based on percentage?

As an updated solution, you can use ColorUtils#blendARGB from the Android support or AndroidX APIs:

val startColor = ContextCompat.getColor(context, R.color.white)
val endColor = ContextCompat.getColor(context, R.color.yellow)
ColorUtils.blendARGB(startColor, endColor, 0.75)

Interpolation like this is best done in HSL or HSV color spaces (and not YUV).

The reason the mid range colours look "muddy" is because if you simply linearly ramp up the red (#ff0000) at the same time as ramping down green (#00ff00) the middle colour ends up as #808000 instead of #ffff00.

Instead, find the HSL (or HSV) equivalent of your starting colour, and the same for the end colour. Interpolate in that colour space, and then for each point convert back to RGB again.

Since the S and L (or V) values are the same for fully saturated red and green, only the H (hue) variable will change, giving the proper effect of a spectrum of colour.


You can try using ArgbEvaluator class from android API: http://developer.android.com/reference/android/animation/ArgbEvaluator.html :

new ArgbEvaluator().evaluate(0.75, 0x00ff00, 0xff0000);

Note that there is a bug ( http://code.google.com/p/android/issues/detail?id=36158 ) in alpha channel calculation so you should use values without alpha value.


My $0.02, I found this answer and coded up the proper solution. (Thanks to Alnitak for the HSV tip!)

For Copy+Paste:

  private float interpolate(float a, float b, float proportion) {
    return (a + ((b - a) * proportion));
  }

  /** Returns an interpoloated color, between <code>a</code> and <code>b</code> */
  private int interpolateColor(int a, int b, float proportion) {
    float[] hsva = new float[3];
    float[] hsvb = new float[3];
    Color.colorToHSV(a, hsva);
    Color.colorToHSV(b, hsvb);
    for (int i = 0; i < 3; i++) {
      hsvb[i] = interpolate(hsva[i], hsvb[i], proportion);
    }
    return Color.HSVToColor(hsvb);
  }