1.来个需求
最近有个需求,根据用户设置的个人主页背景改变字体颜色,想想这个比根据手机壳改变主题的需求相比还算合理。那就想想怎么做吧。
我想Android 中有个Palette库(implementation ``**'androidx.palette:palette:1.0.0'**
)应该可以做。
我的思路大致如下
1 .利用Palette 获取图片的主色调
Palette.from(bitmap)
.generate { palette ->
if (palette != null) {
val dominantColor = palette.getDominantColor(Color.BLACK)
}
- 然后根据获取的dominantColor 的亮度来设置文字颜色。
val textColor= if(ColorUtils.calculateLuminance(dominantColor)>=0.5) {
//图片主色调是是亮色 则文字颜色就是黑色
Color.BLACK
}else{
Color.WHITE
}
还有一种方案是利用Palette 提供的api 设置文字颜色,但我感觉效果不是很好
val textColor=palette.dominantSwatch?.bodyTextColor?:Color.BLACK
目前我就想到这两种方案,如果大家有比较好的方案,可以在评论区说一说,欢迎大家提供解决方案。
2.遇到个问题,K.O它
在项目中我使用的方案一,测试了几张图片感觉还可以。但是当我测试用比较纯白或者纯黑的图片测试的时候,发现palette.getDominantColor(Color.BLACK)
取到的都是默认值,无法获取图片的主要颜色。
先说说解决方法,就是使用clearFilters()
方法
Palette.from(bitmap)
//清除默认的颜色过滤器
.clearFilters()
.generate { palette ->
if (palette != null) {
val dominantColor = palette.getDominantColor(Color.GRAY)
}
}
下面在说说为啥,那就不得不去看看Palette内部干了些啥事。
filter 的功能是过滤一些颜色,在Palette 构造方法中添加了一个默认过滤器,这个默认过滤器代码实现如下
static final Filter DEFAULT_FILTER = new Filter() {
private static final float BLACK_MAX_LIGHTNESS = 0.05f;
private static final float WHITE_MIN_LIGHTNESS = 0.95f;
@Override
public boolean isAllowed(int rgb, float[] hsl) {
return !isWhite(hsl) && !isBlack(hsl) && !isNearRedILine(hsl);
}
/**
* @return true if the color represents a color which is close to black.
*/
private boolean isBlack(float[] hslColor) {
return hslColor[2] <= BLACK_MAX_LIGHTNESS;
}
/**
* @return true if the color represents a color which is close to white.
*/
private boolean isWhite(float[] hslColor) {
return hslColor[2] >= WHITE_MIN_LIGHTNESS;
}
/**
* @return true if the color lies close to the red side of the I line.
*/
private boolean isNearRedILine(float[] hslColor) {
return hslColor[0] >= 10f && hslColor[0] <= 37f && hslColor[1] <= 0.82f;
}
};
Filter
是了接口 它又一个isAllowed
方法,决定允许获取的颜色。在上面DEFAULT_FILTER
中 的方法定义是不是黑色 且不是白色 还有不是isNearRedILine
(??什么颜色)才可以 通过。所以默认过滤器过滤了黑色和白色,所以导致上面那种问题。
上面是通过方法中是hsl模式(HSL)来表达颜色的。在Android中是通过一个数组长度为3的float 数组表示的
数组下标0 对应的值表示 色相(Hue ) 取值为[0,360]、数组下标1 对应的值表示 饱和度 Saturation 取值范围为[0,1]、数组下标2对应的值表示 亮度 Lightness 取值范围为[0,1]。在Android 的ColorUtils 类中提供了rgb模式下的color转hsl模式的方法 colorToHSL(@ColorInt **int **color, @NonNull float[] outHsl)
参考链接
1.[使用 Palette API 选择颜色](https://developer.android.google.cn/training/material/palette-colors)
2.[使用 Palette 让你的 UI 色彩与内容更贴合](https://segmentfault.com/a/1190000011069612)