一、前言
使用调色板 API,可以获取 Bitmap 图片中的颜色,并提供了六个主要颜色配置。可以通过 Palette API 获取图片中的颜色,然后对整个页面的UI主体风格进行设置。例如根据配图色调更改标题栏颜色、文本内容等等。
二、使用 调色板(Palette) API 选择颜色
2.1 添加 Palette API 支持
Palette API 是一个支持库,需要在项目中添加依赖库才能使用。
dependencies {
// support 库方案
implementation 'com.android.support:palette-v7:28.0.0'
// androidx 库方案
implementation 'androidx.palette:palette:1.0.0'
}
注意事项:
1. support 库方案和 androix 库方案只能选择一种;
2. 在新版本的AndroidStudio中,如果targetSdkVersion 在 29 及以上时,会无法使用 support库方案。
2.2 创建调色板
创建调色板,先通过 Bitmap 实例化一个 Palette.Builder
对象。然后可以通过 Palette.Builder
对象自定义调色板,以达到需要的效果。
2.2.1 生成调色板实例
通过 Palette
类的的 from(Bitmap bitmap)
方法生成 Palette.Builder
实例,然后通过 Palette.Builder
实例的的 generate()
方法获取到调色板实例,generate()
方法包含同步和异步两个版本。
val bm = BitmapFactory.decodeResource(resources, R.drawable.pic)
val palette = Palette.from(bm).generate()
注意事项:如果需要为图片或者对象列表生成调色板,为了提高UI绘制效率,请使用缓存机制。
2.2.2 自定义调色板
通过对 Palette.Builder
进行配置,可以自定义调色板,包括生成调色板的颜色数量(默认值16)、生成调色板对应的图片区域(默认全图)、调色板中可以显示哪些颜色等。Palette.Builder
类中包含以下方法可以对调色板进行微调。
addFilter()
:此方法添加一个过滤器,用于指明生成的调色板中可以有那些颜色,可以定义一个Palette.Filter
并重写isAllowed(int rgb, float[] hsl)
方法,该方法返回一个 boolean 类型值,true 为接受该颜色值,false 为拒绝改颜色值。maximumColorCount()
:此方法用于设定调色板中颜色数量,默认值为16,最佳值取决于原图片,并且调色板颜色数量也可能会小于这个最大值。调色班中的颜色越多,Palette.Builder
生成调色板对象的事件就越长。setRegion()
:这个方法指定创建调色板时针对Bitmap
的区域。这个方法只有在从Bitmap
生成调色板是有效,并且不会影响Bitmap
。addTarget()
:此方法允许开发者向生成工具添加Target
颜色配置文件来执行颜色调整。如果默认的 Target.Builde 不够用,开发者还可以使用Target.Builde
创建自己的Target
。
val palette = Palette.from(bm)
.maximumColorCount(24)
.setRegion(50, 50, 400, 400)
.addFilter(Palette.Filter { rgb, hsl ->
// 这里是isAllowed() 方法,lambda表达式模式
rgb != Color.argb(0xff, 0x28, 0x48, 0x88)
})
.generate()
注意事项:自定义调色板是针对
Palette.Builder
对象,必须在generate()
方法生成Palette
对象之前定义。
2.3 使用调色板的配置
调色板库是用来从图片提取常用的颜色配置文件(默认有六个),每个配置文件都由 Target 定义
。创建调色板对象时,调色板库会针对从位图图片中提取的颜色进行评分,具体评判标准包括饱和度、亮度和填充(由颜色表示的位图像素数),由得分最高的颜色来定义给定图片的颜色配置文件。在默认情况下,调色板对象包含 16 种主要颜色,但是可以通过自定义调色板(参考:自定义调色板)定义提取更多的颜色,已达到提高颜色配置文件的匹配。
调色板库会尝试提取一下六个颜色配置文件,但不一定会提取成功,每个 Palette
对象的 get<Profile>Color()
方法返回与该特定配置文件相关联的调色板中的颜色(可通过 Palette
对象的 get<Profile>Swatch()
方法获取对应的颜色配置的 Palette.Swatch
对象,如果获取失败,配置为 null
,那么对应的配置颜色也只能返回默认颜色)。
-
Light Vibrant(亮鲜艳的):
-
Vibrant(鲜艳的):
-
Dark Vibrant(安鲜艳的):
-
Light Muted(亮柔和的):
-
Muted(柔和的):
-
Dark Muted(暗柔和的):
-
示例
val palette = Palette.from(bm)
.generate(object: Palette.PaletteAsyncListener {
override fun onGenerated(palette: Palette?) {
palette?.apply {
if(null == palette.lightVibrantSwatch) {
tvLightVibrant.setText("未能获取到Light Vibrant颜色配置")
} else {
tvLightVibrant.setBackgroundColor(palette.lightVibrantSwatch!!.rgb)
tvLightVibrant.setTextColor(palette.lightVibrantSwatch!!.bodyTextColor)
tvLightVibrant.setText("Light Vibrant(${color2String(palette.lightVibrantSwatch!!.rgb)})")
}
if(null == palette.vibrantSwatch) {
tvVibrant.setText("未能获取到Vibrant颜色配置")
} else {
tvVibrant.setBackgroundColor(palette.vibrantSwatch!!.rgb)
tvVibrant.setTextColor(palette.vibrantSwatch!!.bodyTextColor)
tvVibrant.setText("Vibrant(${color2String(palette.vibrantSwatch!!.rgb)})")
}
if(null == palette.darkVibrantSwatch) {
tvDarkVibrant.setText("未能获取到Dark Vibrant颜色配置")
} else {
tvDarkVibrant.setBackgroundColor(palette.darkVibrantSwatch!!.rgb)
tvDarkVibrant.setTextColor(palette.darkVibrantSwatch!!.bodyTextColor)
tvDarkVibrant.setText("Dark Vibrant(${color2String(palette.darkVibrantSwatch!!.rgb)})")
}
if(null == palette.lightMutedSwatch) {
tvLightMuted.setText("未能获取到Light Muted颜色配置")
} else {
tvLightMuted.setBackgroundColor(palette.lightMutedSwatch!!.rgb)
tvLightMuted.setTextColor(palette.lightMutedSwatch!!.bodyTextColor)
tvLightMuted.setText("Light Muted(${color2String(palette.lightMutedSwatch!!.rgb)})")
}
if(null == palette.mutedSwatch) {
tvMuted.setText("未能获取到Muted颜色配置")
} else {
tvMuted.setBackgroundColor(palette.mutedSwatch!!.rgb)
tvMuted.setTextColor(palette.mutedSwatch!!.bodyTextColor)
tvMuted.setText("Muted(${color2String(palette.mutedSwatch!!.rgb)})")
}
if(null == palette.darkMutedSwatch) {
tvDarkMuted.setText("未能获取到Dark Muted颜色配置")
} else {
tvDarkMuted.setBackgroundColor(palette.darkMutedSwatch!!.rgb)
tvDarkMuted.setTextColor(palette.darkMutedSwatch!!.bodyTextColor)
tvDarkMuted.setText("Dark Muted(${color2String(palette.darkMutedSwatch!!.rgb)})")
}
palette.swatches.forEach {
Log.e("AAAA", color2String(it.rgb))
}
adapter.addDatas(palette.swatches)
}
}
})
讲解:以上示例中,提取图片中 16 种颜色(默认值),可以看到系统的六个颜色配置文件,只成功提取了三个。如果通过自定义调色板,获取更多的颜色,系统默认的六个颜色配置文件可成功提取的数量就会越多。
2.4 使用色样创建配色方案
Palette
类会为每个颜色配置文件生成 Palette.Swatch
对象,Palette.Swatch
对象包含该配置文件的填充色及关联颜色。前面章节提到,可通过 Palette
对象的 get<Profile>Swatch()
方法获取对应的颜色配置的配色信息(上面提到的六种颜色配置文件),如果需要获取所有色样,可以使用Palette
对象的 getSwatches()
方法。
当我们获取到特定的颜色配置之后,该颜色配置文件会包含色样颜色,以及色样颜色的标题文字颜色、正文文字等配色颜色。使用色样及这些配色,就可以实现根据图片来优化页面的配色方案了。
val palette = Palette.from(bm)
.maximumColorCount(16)
.generate(object : Palette.PaletteAsyncListener {
override fun onGenerated(palette: Palette?) {
palette?.lightVibrantSwatch?.apply {
Log.e("XXXX", "lightVibrant: ${color2String(rgb)}")
supportActionBar?.setBackgroundDrawable(ColorDrawable(palette.lightVibrantSwatch!!.rgb))
}
if (null != palette) {
adapter.addDatas(palette.swatches)
}
}
})
- 实现效果
三、编后语
调色板库的作用是提取图片的色样,用于UI配色方案。例如音乐播放器需要根据封面改变播放界面的配色方案、报刊类根据配图改变配色方案等等,可以提高用户视觉体验。不过需要注意的是,获取图片颜色配置是非常耗时的操作,需要注意优化,防止程序卡顿,造成不好的用户体验。