最近在逛 Android 开发者官网的时候,发现了一个有趣的官方库 Palette
,望文生义,就是调色板了,它是 Jetpack UI 组件的一部分。
为什么觉得有趣,因为它跟我们平时做图片时的取色器一样,能够从一张图片中吸取颜色。
这样说又过于笼统,实际上 Palette
是一个类似调色板的工具,能够根据传入的 Bitmap
,提取出主体颜色,我们可以把提取的颜色融入到 UI 中,使 UI 风格更加美观融洽。
官方文档中就给出了一个应用场景:
For example, a music app could use a
Palette
object to extract the major colors from an album cover, and use those colors to build a color-coordinated song title card.例如,音乐应用可以使用
Palette
对象从影集封面中提取主要颜色,然后使用这些颜色制作颜色协调的歌曲片头字幕。
我打开 EMUI 的系统音乐应用,看到的确有用到相似的效果:
可以看到,该音乐应用随着歌曲的切换,背景和字体颜色都发生了改变,不过它这里的背景似乎并不是从图片中提取颜色,而是将专辑封面放大后添加了一个深色半透明的蒙层,但字体颜色应该是提取自封面的。
话不多说,我们来看看 Palette
的使用。
首先需要导入 Palette
的库:
implementation 'androidx.palette:palette:{version}'
如果项目使用的是 Android Support 库,则该依赖也应切至 Support 版本。
Palette
可以帮助我们从图片中提取多种颜色:
- Vibrant
- Vibrant Dark
- Vibrant Light
- Muted
- Muted Dark
- Muted Light
接下来就需要一张图片,从网络获取或者丢到本地文件夹都可以,我这里选择从本地加载。
使用方法非常简单,只需要将图片转换成 Bitmap
,接下来的一切交给 Palette
。
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.lake_urmia);
Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
if (palette != null) {
Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
if (vibrantSwatch != null) {
vibrant.setBackgroundColor(vibrantSwatch.getRgb());
vibrant.setTextColor(vibrantSwatch.getBodyTextColor());
}
Palette.Swatch darkVibrantSwatch = palette.getDarkVibrantSwatch();
if (darkVibrantSwatch != null) {
vibrantDark.setBackgroundColor(darkVibrantSwatch.getRgb());
vibrantDark.setTextColor(darkVibrantSwatch.getBodyTextColor());
}
Palette.Swatch lightVibrantSwatch = palette.getLightVibrantSwatch();
if (lightVibrantSwatch != null) {
vibrantLight.setBackgroundColor(lightVibrantSwatch.getRgb());
vibrantLight.setTextColor(lightVibrantSwatch.getBodyTextColor());
}
Palette.Swatch mutedSwatch = palette.getMutedSwatch();
if (mutedSwatch != null) {
muted.setBackgroundColor(mutedSwatch.getRgb());
muted.setTextColor(mutedSwatch.getBodyTextColor());
}
Palette.Swatch darkMutedSwatch = palette.getDarkMutedSwatch();
if (darkMutedSwatch != null) {
mutedDark.setBackgroundColor(darkMutedSwatch.getRgb());
mutedDark.setTextColor(darkMutedSwatch.getBodyTextColor());
}
Palette.Swatch lightMutedSwatch = palette.getLightMutedSwatch();
if (lightMutedSwatch != null) {
mutedLight.setBackgroundColor(lightMutedSwatch.getRgb());
mutedLight.setTextColor(lightMutedSwatch.getBodyTextColor());
}
}
}
});
效果如下:
可以看到,Palette
从图片调色板中也解析到了对应的 6 组 Swatch
,每组 Swatch
中包含了多种颜色,同时也提供了获取最终颜色的方法,其中 getPopulation()
表示样本中的像素数量,getRgb()
和 getHsl()
分别是获取颜色的 RGB 值和 HSL 值,getBodyTextColor()
和 getTitleTextColor()
则分别是该颜色下标题和正文所适合的字体颜色。
这里提几个需要注意的点。
一是注意判空,可以看到上面的示例代码中有多处判空,首先是回调得到的 Palette
有可能为空,所以要做判空,同时通过 Palette
解析得到的 Swatch
也可能为空,因为并不是所有图片的色彩都足够丰富以得到这 6 种 Swatch
,如果不判空则可能会导致应用崩溃。
二是异步,Palette
除了上方示例的通过 Palette.PaletteAsyncListener()
回调的方法外,还有一个无参的 generate()
方法,不难知道知道分别是异步和同步生成。为什么需要异步,是因为图片过大或者色彩过于丰富的情况下解析有可能会阻塞线程,所以更倾向于使用异步的方式,当然你也可以自行构建异步逻辑。