关于Android配色 自适应颜色的实现

在Android4.4系统中,更加详细地介绍了关于颜色的细节并提供了使用colour的新教程,以使我们的应用更加独一无二。也就是说,作为一个设计师或者开发者,为你的APP做完美的配色已经变成了你的职责。

可以通过改变Android Framework界面元素的默认蓝色来使应用更加独特。 ——来自Android Design

最简单的方式就是给Action Bar加上一层自定义的背景,但是在我现在写的一个APP中我希望可以更灵活一些(做到自适应),自适应颜色的最好例子就是iTunes了,它会从专辑中获取配色方案,作用于弹出的曲目列表。

所以,我准备在Android上实现这个技术。

基本理论知识

在网上搜索一遍后,我发现了很多开源的实现方式,不过是用其他语言写的。最好的版本是一个JavaScript库,叫Color Thief,我从里面学到了很多实现这个技术需要的知识,正好是我需要的。

图像量化

这里要做的第一步就是量化源图像,通俗地说,就是减少图像上使用的颜色种类。如果你喜欢动态的GIF,那么只能用8位的色板,所以每一帧最多可以使用256种颜色。

为此,我们就需要减少颜色使用,只使用一些主要的颜色,那我们就用默认的色板吧,再根据需要弄出一些其他的颜色。稍后将详细介绍。

现在需要选择量化算法了,Color Thief用了一个修改版的MCQ(Median Cut Quantization)算法,另称作MMCQ(Modified Median Cut Quantization),如果想了解更多关于MMCQ的信息,可以来 这里 。其他的比较著名的量化技术还有NeuQuantOctTree

我还在《Principles of Digital Image Processing 》这本书上找到了一个JAVA的MCQ实现,托管在GitHub上。

这个MCQ算法有很多很棒的特性,所以我决定就用它了:

  • 它很快。它比NeuQuant和OctTree还快,在移动设备上这点尤其重要;
  • 它内部使用了统计直方图,每种色块都绑定了一个数值,之后排序的时候更方便。

虽然MCQ算法生成的图像质量不是最好的,但是这里只是需要它生成的调色板,不用展示生成的图像,所以,还不错。

处理结果

以下就是处理后的结果,使用Color Thief的例子里的图像。之前说过MCQ里面带有统计直方图,所以我们可以排列出每种颜色使用的频率,它显示了调色板排序后的列表。当然,这还是可以继续改进。

这些结果和Color Thief生成的图像有点不一样:

  • 我的版本选择蓝色作为主要的颜色;
  • Color Thief挑选了蓝色,银色和绿色作为主要颜色;
  • Color Thief没有选到那些灰色的阴影。所以还需要改进。

接着上文讲的,可以调用MedianCutQuantizer对象的getQuantizedColors()这个方法可以获取调色板。我们可以以颜色使用的数量和比重来对这个集合进行降序显示。很不幸的是结果表明大多数图像用的颜色是黑色和白色(或相近的颜色),这颜色根本不能让我们的应用显得更独特,所以我们要考虑到底选择什么颜色了。

对于我自己的应用来说,我准备使用以下的调色方案:

  • 第一位的主色是一种鲜艳的颜色;
  • 第二位主色是区别一于第一位主色的另一种亮色;
  • 第三位主色是和第一位和第二位主色对比强烈的颜色;
  • 一种主要的字体颜色,和整体主色对比明显,可读性强;
  • 第二种主要字体颜色就是白色或者黑色,取决于整体主色的亮度,可读性强。

这篇文章主要讲的也就是怎么选择这些颜色。

主色

根据以上我的需求,我决定使用以下因素的平均值:

  • 鲜艳度;
  • 热度(受欢迎程度)。
鲜艳度

这个其实也很简单,首先要把RGB颜色模型转化成HSV颜色模型,使用Android内置的[Color.RGBToHSV()] (https://developer.android.com/reference/android/graphics/Color.html#RGBToHSV(int, int, int, float[]))方法可以做到。如果不明白HSV颜色模型可以看 这里

简单地说,这个圆柱形就代表了RGB颜色模型,通过三个坐标来表示颜色:Hue,Saturation和Value(明度)。

HSV颜色模型,来自 Wikipedia

我使用一个简单的方式去计算鲜艳度,通过饱和度(saturation )和色度(value)。在人眼看来这两个值越高,鲜艳度就越高。

  1. public float[] getHsv() {
  2. float[] hsv = new float[3];
  3. Color.RGBToHSV(r, g, b, hsv);
  4. return hsv;
  5. }
  6. public float calculateColorfulness() {
  7. float[] hsv = getHsv();
  8. return hsv[1] * hsv[2];
  9. }

计算的结果会在0.0到1.0的范围内。

热度

还记得之前说过每个颜色都有一个绑定的值吗?这里可以使用这个值来决定一种颜色在调色板中的受欢迎程度。记住值得范围是在0.0到1.0之间。

也就是说我们得到了如下的简单的调色板:

|  Color   |  Count  |
----------------------
|  White   |   200   |
|  Purple  |   175   |
|  Black   |   150   |
|  Red     |   125   |
|  Orange  |   100   |
|  Blue    |    50   |
----------------------
|  Total   |   800   |

我们可以通过图像中的这个比例来计算出颜色占有的比例,上图中有800像素,以紫色为例,它的颜色比例为:175 / 800 = ~0.22。可是这个值很小,只能接近1而已。

反之我们可以选择调色板中最受欢迎的颜色作为基准来计算这个比例。还是用上一个例子,白色是最受欢迎的颜色,所以紫色的比例就是:175 / 200 = 0.87。相对于颜色的受欢迎程度来说,这个更具代表性。

最终值

这里要使用这些值来结合成一个最终的值,这样简单合成没有问题,但是之前说了黑白色是最受欢迎的颜色,考虑到这个,这里我们做一个权重,来决定一些属性的重要程度,这种情况下我们提高了鲜艳度:

  1. static float weightedAverage(float... values) {
  2. assert values.length % 2 == 0;
  3. float sum = 0;
  4. float sumWeight = 0;
  5. for (int i = 0; i = SECONDARY_MIN_DIFF_HUE_PRIMARY) {
  6. return candidate;
  7. }
  8. }
  9. // If we get here, just return the second weighted color
  10. return mWeightedPalette[1];

第三位主色

这种颜色和上面第二位主色很相似,但是这次就不找Hue值了,我们直接对比前两种颜色就可以了。

  1. // Contrast values are in the range 0-255.
  2. private static final int TERTIARY_MIN_CONTRAST_PRIMARY = 20;
  3. private static final int TERTIARY_MIN_CONTRAST_SECONDARY = 90;
  4. ...
  5. // Find the first color which has sufficient contrast from both the primary & secondary
  6. for (ColorNode color : mWeightedPalette) {
  7. if (ColorUtils.calculateContrast(color, primary)
  8. >= TERTIARY_MIN_CONTRAST_PRIMARY
  9. && ColorUtils.calculateContrast(color, secondary)
  10. >= TERTIARY_MIN_CONTRAST_SECONDARY) {
  11. return color.getRgb();
  12. }
  13. }
  14. // We couldn‘t find a colour. In that case use the primary colour, modifying it‘s
  15. // brightness by 45%
  16. return ColorUtils.changeBrightness(secondary.getRgb(), 0.45f);

来看一下,calculateContrast()这个方法哪来的?这个我也想了很久,其实它来自这篇文章color contrast

最后我再把RGB颜色模型转换成了YIQ颜色模型,仅仅携带了Y(亮度)值,之后你可以对比下两种颜色的亮度值,看看在明度上有什么不一样,再用临界值来试试。

  1. /**
  2. * @return difference in luma. Possible values are 0 (no difference) to
  3. *         255 (max difference).
  4. */
  5. private static final int calculateContrast(int rgbColor1, int rgbColor2) {
  6. return Math.abs(calculateYiqLuma(rgbColor1) - calculateYiqLuma(rgbColor2));
  7. }
  8. /**
  9. * @return luma value. Values are in the range 0-255.
  10. */
  11. public static final int calculateYiqLuma(int color) {
  12. return (299 * Color.red(color) + 587 * Color.green(color) + 114 * Color.green(color)) / 1000;
  13. }

代码

我说过要发代码的,看这里:

https://gist.github.com/chrisbanes/ba8e7b9ec0e40f6949c6

这代码也许跑不起来,所以需要修改一下然后包含到你的APP中,这是仅仅是为了让你知道怎么把它集成到APP中,所有重要的东西都在这里了,你只需要考虑怎么集成进你的APP就行了。加油吧。

原文链接: banes   翻译: 伯乐在线 - chris

译文链接: http://blog.jobbole.com/64715/

时间: 2024-08-09 03:14:37

关于Android配色 自适应颜色的实现的相关文章

Android内置颜色及其它颜色RGB对照表

参考:http://blog.csdn.net/feiyangxiaomi/article/details/38338305 我们在平时开发时经常要用到各种颜色,有了下面这两张表,妈妈再也不用担心你的配色问题了. 一:内置颜色: public static final int BLACK Added in API level 1 Constant Value: -16777216 (0xff000000)        public static final int BLUE Added in 

android 设置字体颜色、EditText自动输入转换成大写字母的多种方式

在TextView上面设置某一个字的字体颜色为指定颜色时,可以通过java类SpannableString类和Html语言来实现. (一)SpannableString类方式 private void setText(TextView t){ String text = t.getText().toString().trim(); SpannableString span = new SpannableString(text); span.setSpan(new ForegroundColorS

android中的颜色设置

1.在android中经常看到设置的颜色为八位的十六进制的颜色值,例如: 1 2 3 public static final class color {     public static final int lightblue=0x7f040000; } 或者在Java中tx.setTextColor(0xffff00f); 说明: 0xffff00ff是int类型的数据,分组一下0x|ff|ff00ff,0x表示颜色整数的标记,ff表示透明度,f00f表示色值,注意:0x后面ffff00ff

Android -- Webview自适应屏幕

第一种                                                                                          WebSetting settings = webView.getSettings(); settings.setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); 把所有内容放在webview等宽的一列中.(可能会出现页面中链接失效) 第二种             

Android基础知识颜色的不透明度和RGB颜色十六进制值

Android中的颜色使用形式为"#FFBFBFCC"(html)和0xFF777777(代码).颜色用8位十六进制数数来表示,前2位表示Alpha 分量(遮光度或者叫不透明度),剩下的6位是R.G.B的分量,两两一组形成指定的颜色,颜色中字母不区分大小写. 2位不透明度值,FF表示完全不透明,00表示完全透明,所以不透明度在00~FF之间,也就是在0~255之间.所以如果你需要60%的不透明度时,可以255*60% = 153,把153转化为十六进制就是99,那么最前面2位就是99了

android tv 实现颜色条滚动效果

直接贴代码: ColorView.java package com.xxx.demo; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Log; import android.view.V

Android中的颜色

来自 http://www.cnblogs.com/bluestorm/p/3644669.html Android中的颜色设置 1.在android中经常看到设置的颜色为八位的十六进制的颜色值,例如: 1 2 3 public static final class color {     public static final int lightblue=0x7f040000; } 或者在Java中tx.setTextColor(0xffff00f); 说明: 0xffff00ff是int类型

修改Android EditText光标颜色

EditText有一个属性:android:textCursorDrawable,这个属性是用来控制光标颜色的 android:textCursorDrawable="@null","@null"作用是让光标颜色和text color一样 修改Android EditText光标颜色

Android EditText光标颜色 与inputType

1.EditText有一个属性:android:textCursorDrawable,这个属性是用来控制光标颜色的 android:textCursorDrawable="@null","@null"作用是让光标颜色和text color一样 2.android 1.5以后添加了软件虚拟键盘的功能,所以在输入提示中将会有对应的软键盘模式android中inputType属性在EditText输入值时启动的虚拟键盘的风格有着重要的作用.这也大大的方便的操作.有时需要虚