材料设计调色板

时间:2015-10-05 06:30:02

标签: android colors material-design

Google设计了一个color palette。给定一种颜色,我想在Android中动态创建调色板。

Graphic Design sitean open source javascript solution中存在类似的问题,会生成类似的调色板。找到每种颜色的因子here,用于创建颜色的函数可在this stackoverflow answer中找到。

我用这个答案和项目来生成一个类似于谷歌的调色板。但是,我想要一个能够返回Google生成的确切值的算法(参见第一个链接)。

问题:Google如何计算材料设计的调色板颜色?

到目前为止我尝试过:

根据上面的信息,我创建了这个例子,以展示我是如何生成类似的调色板的。同样,我想要准确的值。

import android.app.Activity;
import android.app.AlertDialog;
import android.graphics.Color;
import android.os.AsyncTask;
import android.view.Gravity;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;

import java.lang.ref.WeakReference;
import java.util.LinkedList;
import java.util.List;

/**
 * @author Jared Rummler <jared.rummler@gmail.com>
 */
public class PaletteTask extends AsyncTask<Integer, Void, List<PaletteTask.Shade>> {

  private static int shadeColor(int color, double percent) {
    return shadeColor(String.format("#%06X", (0xFFFFFF & color)), percent);
  }

  private static int shadeColor(String color, double percent) {
    long f = Long.parseLong(color.substring(1), 16);
    double t = percent < 0 ? 0 : 255;
    double p = percent < 0 ? percent * -1 : percent;
    long R = f >> 16;
    long G = f >> 8 & 0x00FF;
    long B = f & 0x0000FF;
    int red = (int) (Math.round((t - R) * p) + R);
    int green = (int) (Math.round((t - G) * p) + G);
    int blue = (int) (Math.round((t - B) * p) + B);
    return Color.rgb(red, green, blue);
  }

  private final WeakReference<Activity> activityWeakReference;

  private final List<Shade> shades = new LinkedList<>();

  {
    shades.add(new Shade(0.9, "50"));
    shades.add(new Shade(0.7, "100"));
    shades.add(new Shade(0.5, "200"));
    shades.add(new Shade(0.333, "300"));
    shades.add(new Shade(0.166, "400"));
    shades.add(new Shade(0, "500"));
    shades.add(new Shade(-0.125, "600"));
    shades.add(new Shade(-0.25, "700"));
    shades.add(new Shade(-0.375, "800"));
    shades.add(new Shade(-0.5, "900"));
    shades.add(new Shade(0.7, "A100"));
    shades.add(new Shade(0.5, "A200"));
    shades.add(new Shade(0.166, "A400"));
    shades.add(new Shade(-0.25, "A700"));
  }

  public PaletteTask(Activity activity) {
    activityWeakReference = new WeakReference<>(activity);
  }

  @Override protected List<Shade> doInBackground(Integer... colors) {

    for (Shade shade : shades) {
      shade.color = shadeColor(colors[0], shade.percent);
    }

    return shades;
  }

  @Override protected void onPostExecute(List<Shade> shades) {
    Activity activity = activityWeakReference.get();
    if (activity == null || activity.isFinishing()) {
      return;
    }

    // Create a dialog that shows our generated colors:

    ScrollView scrollView = new ScrollView(activity);
    LinearLayout linearLayout = new LinearLayout(activity);
    linearLayout.setOrientation(LinearLayout.VERTICAL);

    int width, height;
    width = LinearLayout.LayoutParams.MATCH_PARENT;
    height = (int) (30/*dp*/ * (activity.getResources().getDisplayMetrics().densityDpi / 160f));

    // add each color
    for (Shade shade : shades) {
      LinearLayout layoutColor = new LinearLayout(activity);
      TextView textView = new TextView(activity);

      layoutColor.setLayoutParams(new LinearLayout.LayoutParams(width, height));
      layoutColor.setBackgroundColor(shade.color);
      layoutColor.setGravity(Gravity.CENTER);

      textView.setText(shade.name + "    " + String.format("#%06X", (0xFFFFFF & shade.color)));

      layoutColor.addView(textView);
      linearLayout.addView(layoutColor);
    }

    scrollView.addView(linearLayout);

    new AlertDialog.Builder(activity).setView(scrollView).show();
  }

  public static class Shade {

    final double percent;
    final String name;
    int color;

    public Shade(double percent, String name) {
      this.percent = percent;
      this.name = name;
    }
  }

}

调用AsynTask

int materialRed500 = 0xFFF44336;
new PaletteTask(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, materialRed500);

根据以上代码创建的对话框:

color palette dialog

2 个答案:

答案 0 :(得分:6)

底线,您无法使用与相应的Google Material Design Palette完全匹配的单一颜色生成调色板

这是因为调色板都遵循不同的颜色进展。例如,使用以下进程生成红色调色板(使用TinyColor.js的JS代码,但您仍然可以看到HSL修改):

return [
            { hex : tinycolor( hex ).lighten( 37.7 ).saturate( 10.4 ).spin( -13 ).toHexString(), name : '50' },
            { hex : tinycolor( hex ).lighten( 31.8 ).saturate( 10.4 ).spin( -9.5 ).toHexString(), name : '100' },
            { hex : tinycolor( hex ).lighten( 18.7 ).desaturate( 17 ).spin( -3.9 ).toHexString(), name : '200' },
            { hex : tinycolor( hex ).lighten( 9.1 ).desaturate( 20.9 ).spin( -4 ).toHexString(), name : '300' },
            { hex : tinycolor( hex ).lighten( 4.1 ).desaturate( 6.6 ).spin( -3 ).toHexString(), name : '400' },
            { hex : hex, name : '500' },
            { hex : tinycolor( hex ).darken( 3.1 ).desaturate( 12.4 ).spin( -2.7 ).toHexString(), name: '600' },
            { hex : tinycolor( hex ).darken( 7.8 ).desaturate( 24.5 ).spin( -4 ).toHexString(), name: '700' },
            { hex : tinycolor( hex ).darken( 11.7 ).desaturate( 23.2 ).spin( -4 ).toHexString(), name: '800' },
            { hex : tinycolor( hex ).darken( 17 ).desaturate( 16.1 ).spin( -4 ).toHexString(), name: '900' },
            { hex : tinycolor( hex ).lighten( 16.7 ).saturate( 10.4 ).spin( 0.6 ).toHexString(), name: 'A100' },
            { hex : tinycolor( hex ).lighten( 7.7 ).saturate( 10.4 ).spin( -4 ).toHexString(), name: 'A200' },
            { hex : tinycolor( hex ).darken( 3.9 ).saturate( 10.4 ).spin( -15.5 ).toHexString(), name: 'A400' },
            { hex : tinycolor( hex ).darken( 16.6 ).saturate( 10.4 ).spin( -4 ).toHexString(), name: 'A700' }
        ];

但是,当您将相同的进展应用于Indigo基色(500)时,您可以看到调色板根本不匹配。在下图中,最左边的调色板是默认的MD调色板,左边的第二个调色板是使用上述进度生成的调色板。这两个调色板完全匹配。当我加载MD Indigo调色板(第三个调色板),然后使用Indigo 500值和红色调色板渐进代码生成调色板时,它会创建第4个调色板。正如你所看到的,虽然这种进展对于红色来说是完全正确的,但对于其他颜色来说还是如此:

enter image description here

有关此主题的更多信息,请here谷歌选择的颜色很可能是由设计师亲自挑选的,而不是以编程方式生成的。

编辑:此外,该MCG的代码已经完全修改。可以找到颜色的新逻辑here,并使用tinycolor.js作为修改函数。

答案 1 :(得分:1)

接受的答案中的逻辑是错误的。它不会为您生成真实的材料颜色。有一个官方的材质调色板工具here。如果需要,可以尝试比较。

不幸的是,谷歌没有提供上述工具的库,这是一个经过精简和打包的javascript文件,其中包含redux。我和我的同事,我们进行了逆向工程,以获得仅产生颜色的零件,您可以here进行查看。请记住,这不是我的代码。

您可以尝试here 与以下行。

materialColorPicker('00ff00')

此调色板具有所选颜色的不同色调,分别是:50、100、200、300、400、500、600、700、800、900 但是给定的颜色可以是这些色调中的任何一种。

例如,如果您选择红色,则此调色板将为您提供以下设置。

50: "ffe7e6"
100: "ffc7b8"
200: "ffa28a"
300: "ff795b"
400: "ff5436"
500: "ff200c"
600: "ff1507"
700: "ff0000" // input colour
800: "f10000"
900: "da0000" 

但是,如果您选择#17996b的颜色,则调色板将产生以下值:

50: "e0f3ec"
100: "b4e0cf"
200: "84cdb1"
300: "54b893"
400: "32a97f"
500: "17996b" // input colour
600: "138c60"
700: "0d7c52"
800: "016c45"
900: "00502a"

如您所见,您认为是原色的输入色可以是任何一种原色。