以编程方式生成 Material 设计颜色集的方法有哪些?

What are the ways to programmatically generate Material Design color sets?

我正在尝试创建一个 Material 设计的调色板,该调色板使用任意十六进制颜色按百分比更改亮度/亮度。当涉及到实现时,我发现有些颜色十六进制我无法生成并显示颜色未知异常。请告诉我生成这组颜色的替代方法或技术预防措施是什么?

以下是我的代码

package com.example.dino.util;

import android.content.Context;
import android.graphics.Color;

import java.util.ArrayList;

/**
 * Created by larrylo on 18/1/15.
 */

public  class ColorUtils {

    public Context context;

    public static float[]  colorToHsl(String hexColor) {
        int color = Color.parseColor(hexColor);
        float r = ((0x00ff0000 & color) >> 16) / 255.0F;
        float g = ((0x0000ff00 & color) >> 8) / 255.0F;
        float b = ((0x000000ff & color)) / 255.0F;
        float max = Math.max(Math.max(r, g), b);
        float min = Math.min(Math.min(r, g), b);
        float c = max - min;

        float hTemp = 0.0F;
        if (c == 0) {
            hTemp = 0;
        } else if (max == r) {
            hTemp = (float) (g - b) / c;
            if (hTemp < 0)
                hTemp += 6.0F;
        } else if (max == g) {
            hTemp = (float) (b - r) / c + 2.0F;
        } else if (max == b) {
            hTemp = (float) (r - g) / c + 4.0F;
        }
        float h = 60.0F * hTemp;

        float l = (max + min) * 0.5F;

        float s;
        if (c == 0) {
            s = 0.0F;
        } else {
            s = c / (1 - Math.abs(2.0F * l - 1.0F));
        }

        float []  hsl  = {h , s , l } ;
        return hsl;
    }



    public static String hslToColor(int alpha, float hue, float saturation, float lightness) {
        float hh = hue;
        float ss = saturation;
        float ll = lightness;
        float h, s, v;
        h = hh;
        ll *= 2;
        ss *= (ll <= 1) ? Ll : 2 - ll;
        v = (ll + ss) / 2;
        s = ((ll + ss) != 0) ? (2 * ss) / (ll + ss) : 0;
        int resultColorInt =  Color.HSVToColor(alpha, new float[] { h, s, v });
        return Integer.toHexString(resultColorInt).toUpperCase();
    }

    public static ArrayList<String> returnMaterialDesignColorSet (String colorHex){
        ArrayList<String> resultList = new ArrayList<String>();
        float [] baseColorHSL = colorToHsl(colorHex);
        double randomMid = randomWithRange(0.48 , 0.52);
        String baseColor = hslToColor(1 ,baseColorHSL[0] , baseColorHSL[1] , (float)0.5);
        resultList.add(baseColor);
        return resultList;
    }

    public static double randomWithRange(double min, double max)
    {
        double range = Math.abs(max - min);
        return (Math.random() * range) + (min <= max ? Min : max);
    }

    public static int colorInt (String hex){
        return Color.parseColor(hex);
    }
}

测试代码

 ActionBar actionBar = getActionBar();
        actionBar.setDisplayHomeAsUpEnabled(true);
        actionBar.setHomeButtonEnabled(true);
        double max = 0.52;
        double min = 0.48;
        double range = Math.abs(max - min);
        double value =  (Math.random() * range) + (min <= max ? Min : max);
        float result = (float)value;
        System.out.println(result);
        String test  = "#973f5c";
        String test2 = ColorUtils.returnMaterialDesignColorSet(test).get(0);
        int colorInt = ColorUtils.colorInt(test2);

        actionBar .setBackgroundDrawable(new ColorDrawable(colorInt));

问题出在以下几行:

int resultColorInt =  Color.HSVToColor(alpha, new float[] { h, s, v });
return Integer.toHexString(resultColorInt).toUpperCase();

当alpha值小于16(0xF0)时,只占字符串中的一个字符:

// 1-char alpha
int resultColorInt =  Color.HSVToColor(1, new float[]{340, 0.7f, 0.5f});
String result = Integer.toHexString(resultColorInt).toUpperCase();
// result == "1802644" - 7 chars, which is invalid color format

您需要通过在结果字符串的开头附加 0 来补偿 1 个字符或 0 个字符的字母(在 0-15 范围内):

// not the best code, but works
while (result.length() < 8) {
    result = "0" + result;
}

// don't forget # to make it a legal color
result = "#" + result;
return result;

但是,最好的办法是完全避免使用字符串。改用整数——它们包含相同的数据,但性能更好。为了您的方便,在调试器中,您可以将整数更改为以 HEX 显示,而不是 DEC(在 Android Studio 中:右键单击变量视图,查看为 -> HEX)。

原始问题

您的代码在使用颜色格式时出错。 如下所示替换 hslToColor() 的最后一行,您将使其 运行 没有错误:

public static String hslToColor(int alpha, float hue, float saturation, float lightness) {

    ...

    // !!! ERROR WAS ON THE LAST LINE:
    return String.format("#%08x", resultColorInt).toUpperCase();
}

我已经测试过了 - 它可以工作 - 因为它还有 2 个额外的功能:
1) 将值格式化为 8 位
2) 添加“#”前缀

您的代码中可能存在第二个问题

alpha 值可以具有从 0(透明)到 255(不透明)的值。如果你想要不透明的图像,你应该传递 255 (0xFF)。
现在你传递 1 我认为这是一个错误 - 因为它几乎是透明的。
所以要用不透明的颜色替换线

String baseColor = hslToColor(1 ,baseColorHSL[0] , baseColorHSL[1] , (float)0.5);

String baseColor = hslToColor(0xFF ,baseColorHSL[0] , baseColorHSL[1] , (float)0.5);

附件
如果需要获得一组颜色 - 应该应用一点创意。
要创建色调调色板,您必须循环更改 a) 饱和度或 b) 亮度或 c)他们两个。
这是一个实现示例,returns 基于亮度的调色板在 10 个步骤中从 0.4 变为 0.6(不包含)。
"Experimental"意味着你应该为自己找到价值。

public static ArrayList<String> returnMaterialDesignColorSet(String baseColorHex, int colorCount) {
    ArrayList<String> resultList = new ArrayList<String>();
     float [] baseColorHSL = colorToHsl(baseColorHex);

    float lght=0.4;// initial lightness value (experimental)
    float lStep=(0.6 - lght) / colorCount; // step to go up to 0.6 lightness (experimental)
    for (int i = 0; i < colorCount; i++) {
         String baseColor = hslToColor(1 ,baseColorHSL[0] , baseColorHSL[1] , lght);
         resultList.add(baseColor);
         lght += lStep;
    }

    return resultList;
}