Java 两种颜色之间的android颜色,基于百分比?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4414673/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 17:13:11  来源:igfitidea点击:

android color between two colors, based on percentage?

javaandroidcolors

提问by Stuck

I would like to calculate the color depending on a percentage value:

我想根据百分比值计算颜色:

float percentage = x/total;
int color;
if (percentage >= 0.95) {
  color = Color.GREEN;
} else if (percentage <= 0.5) {
  color = Color.RED;
} else {
  // color = getColor(Color.Green, Color.RED, percentage);
}

How can I calculate that last thing? It would be OK if yellow appears at 50%.

我如何计算最后一件事?如果黄色出现在 50% 就可以了。

I tried this:

我试过这个:

private int getColor(int c0, int c1, float p) {
    int a = ave(Color.alpha(c0), Color.alpha(c1), p);
    int r = ave(Color.red(c0), Color.red(c1), p);
    int g = ave(Color.green(c0), Color.green(c1), p);
    int b = ave(Color.blue(c0), Color.blue(c1), p);
    return Color.argb(a, r, g, b);
}
private int ave(int src, int dst, float p) {
    return src + java.lang.Math.round(p * (dst - src));
}

Well this works, but I would like the colors at around 50% being more lightend as I use them on a grey background.. how can I accomplish that?

嗯,这是可行的,但我希望 50% 左右的颜色更亮,因为我在灰色背景上使用它们..我怎样才能做到这一点?

Thanks!

谢谢!

UPDATEI tried to convert to YUV like it was suggested in the comments. But I still have the same problem that at 50% it's to dark. Additional in this solution I have at <5% now white as color. If I do not calculate float y = ave(...);, but just take float y = c0.yit's a little better, but at <20% I have then cyan color ... I'm not so much into color-formats :-/ Maybe I'm doing something wrong in the calculation? The constants are taken from Wikipedia

更新我尝试像评论中建议的那样转换为 YUV。但我仍然有同样的问题,在 50% 时它会变黑。在这个解决方案中,我现在有 <5% 的白色作为颜色。如果我不计算float y = ave(...);,但只是float y = c0.y稍微好一点,但在 <20% 时我有青色......我不太喜欢颜色格式:-/ 也许我在计算中做错了什么? 常数取自维基百科

public class ColorUtils {

    private static class Yuv {
        public float y;
        public float u;
        public float v;

        public Yuv(int c) {
            int r = Color.red(c);
            int g = Color.green(c);
            int b = Color.blue(c);
            this.y = 0.299f * r + 0.587f * g + 0.114f * b;
            this.u = (b - y) * 0.493f;
            this.v = (r - y) * 0.877f;
        }
    }

    public static int getColor(int color0, int color1, float p) {
        Yuv c0 = new Yuv(color0);
        Yuv c1 = new Yuv(color1);
        float y = ave(c0.y, c1.y, p);
        float u = ave(c0.u, c1.u, p);
        float v = ave(c0.v, c1.v, p);

        int b = (int) (y + u / 0.493f);
        int r = (int) (y + v / 0.877f);
        int g = (int) (1.7f * y - 0.509f * r - 0.194f * b);

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

    private static float ave(float src, float dst, float p) {
        return src + Math.round(p * (dst - src));
    }
}

采纳答案by Stuck

Ok, after 2 hours of converting to yuv, hsv, etc pp... I give up. I now do it just like this:

好的,在转换为 yuv、hsv 等 pp 2 小时后......我放弃了。我现在这样做:

public class ColorUtils {
    private static int FIRST_COLOR = Color.GREEN;
    private static int SECOND_COLOR = Color.YELLOW;
    private static int THIRD_COLOR = Color.RED;

    public static int getColor(float p) {
        int c0;
        int c1;
        if (p <= 0.5f) {
            p *= 2;
            c0 = FIRST_COLOR;
            c1 = SECOND_COLOR;
        } else {
            p = (p - 0.5f) * 2;
            c0 = SECOND_COLOR;
            c1 = THIRD_COLOR;
        }
        int a = ave(Color.alpha(c0), Color.alpha(c1), p);
        int r = ave(Color.red(c0), Color.red(c1), p);
        int g = ave(Color.green(c0), Color.green(c1), p);
        int b = ave(Color.blue(c0), Color.blue(c1), p);
        return Color.argb(a, r, g, b);
    }

    private static int ave(int src, int dst, float p) {
        return src + java.lang.Math.round(p * (dst - src));
    }
}

By explicity using yellow as the middle color, the generated colors are brighter :-)

通过明确使用黄色作为中间色,生成的颜色更亮:-)

Anyway.. if someone has a good other solution, I would appreciate it.

无论如何..如果有人有其他好的解决方案,我将不胜感激。

回答by Christopher O.

Here is a pseudocode function that interpolates linearly between 2 colors (staying in RGB space). I'm using a class called Color here instead of ints for clarity.

这是一个在两种颜色之间线性插值的伪代码函数(staying in RGB space)。为清楚起见,我在这里使用了一个名为 Color 的类,而不是 ints。

bAmount is between 0 and 1 (for interpolation)

bAmount 介于 0 和 1 之间(用于插值)

Color interpolate(Color colorA, Color colorB, float bAmount) {
    Color colorOut;
    float aAmount = 1.0 - bAmount;
    colorOut.r =  colorA.r * aAmount + colorB.r * bAmount;
    colorOut.g =  colorA.g * aAmount + colorB.g * bAmount;
    colorOut.b =  colorA.b * aAmount + colorB.b * bAmount;
    return colorOut;
}

回答by Alnitak

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

像这样的插值最好在HSL 或 HSV颜色空间(而不是 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 #808000instead of #ffff00.

中间范围颜色看起来“浑浊”的原因是,如果您#ff0000在降低绿色 ( #00ff00) 的同时简单地线性增加红色 ( ) ,则中间颜色最终会变成#808000而不是#ffff00

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

相反,找到与您的起始颜色等效的 HSL(或 HSV),并找到与结束颜色相同的 HSL(或 HSV)。在颜色空间中进行插值,然后为每个点再次转换回 RGB。

Since the Sand 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 spectrumof colour.

由于完全饱和的红色和绿色的SL(或V)值相同,因此只有H(色调)变量会发生变化,从而产生正确的颜色光谱效果。

回答by Mark Renouf

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

我的 0.02 美元,我找到了这个答案并编写了正确的解决方案。(感谢 Alnitak 提供 HSV 提示!)

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

回答by Equidamoid

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

您可以尝试使用来自 android API 的 ArgbEvaluator 类: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.

请注意,alpha 通道计算中存在一个错误 ( http://code.google.com/p/android/issues/detail?id=36158),因此您应该使用没有 alpha 值的值。

回答by android developer

Here are 2 ways to interpolate:

这里有两种插值方法:

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

/** Returns an interpoloated color, between <code>a</code> and <code>b</code> */
public static int interpolateColorHsv(final int a, final int b, final float proportion) {
    final float[] hsva = new float[3];
    final 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);
}

public static int interpolateRGB(final int colorA, final int colorB, final float bAmount) {
    final float aAmount = 1.0f - bAmount;
    final int red = (int) (Color.red(colorA) * aAmount + Color.red(colorB) * bAmount);
    final int green = (int) (Color.green(colorA) * aAmount + Color.green(colorB) * bAmount);
    final int blue = (int) (Color.blue(colorA) * aAmount + Color.blue(colorB) * bAmount);
    return Color.rgb(red, green, blue);
}

回答by tir38

I just wanted to update Mark Renouf's answerto handle alpha channel as well:

我只是想更新Mark Renouf 的答案来处理 alpha 通道:

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

回答by J.S.R - Silicornio

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;
}

回答by mrstif

As an updated solution, you can use ColorUtils#blendARGBfrom the Android supportor AndroidXAPIs:

作为一个更新的解决方案,您可以使用ColorUtils#blendARGB支持AndroidAndroidX的API:

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