I would like to calculate the color depending on a percentage value:
float percentage = x/total;
int color;
if (percentage >= 0.95) {
color = Color.GREE
I just wanted to update Mark Renouf's answer to handle alpha channel as well:
private float interpolate(float a, float b, float proportion) {
return (a + ((b - a) * proportion));
}
/**
* Returns an interpolated color, between <code>a</code> and <code>b</code>
* proportion = 0, results in color a
* proportion = 1, results in color b
*/
private int interpolateColor(int a, int b, float proportion) {
if (proportion > 1 || proportion < 0) {
throw new IllegalArgumentException("proportion must be [0 - 1]");
}
float[] hsva = new float[3];
float[] hsvb = new float[3];
float[] hsv_output = new float[3];
Color.colorToHSV(a, hsva);
Color.colorToHSV(b, hsvb);
for (int i = 0; i < 3; i++) {
hsv_output[i] = interpolate(hsva[i], hsvb[i], proportion);
}
int alpha_a = Color.alpha(a);
int alpha_b = Color.alpha(b);
float alpha_output = interpolate(alpha_a, alpha_b, proportion);
return Color.HSVToColor((int) alpha_output, hsv_output);
}
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)
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.
Some of solutions of this thread didn't work for me, so I create another solution. Maybe it is useful for someone.
/**
* Get the color between two given colors
* @param colorStart int color start of degradate
* @param colorEnd int color end of degradate
* @param percent int percent to apply (0 to 100)
* @return int color of degradate for given percent
*/
public static int getColorOfDegradate(int colorStart, int colorEnd, int percent){
return Color.rgb(
getColorOfDegradateCalculation(Color.red(colorStart), Color.red(colorEnd), percent),
getColorOfDegradateCalculation(Color.green(colorStart), Color.green(colorEnd), percent),
getColorOfDegradateCalculation(Color.blue(colorStart), Color.blue(colorEnd), percent)
);
}
private static int getColorOfDegradateCalculation(int colorStart, int colorEnd, int percent){
return ((Math.min(colorStart, colorEnd)*(100-percent)) + (Math.max(colorStart, colorEnd)*percent)) / 100;
}
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.
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);
}