使用 Palette 让你的 UI 色彩与内容更贴合

版权声明:android

本帐号发布文章均来自公众号,承香墨影(cxmyDev),版权归承香墨影全部。app

每周会统一更新到这里,若是喜欢,可关注公众号获取最新文章。函数

未经容许,不得转载。字体

1、前言

今天介绍一个 Android 下比较有意思的 Support v7 库,Palette,它翻译过来就是调色板。ui

Palette 能够从一张 Bitmap 中提取出它突出的颜色,这样咱们就能够将提取出来的颜色设置在 App 的固定 UI 中(例如:ToolBar 的背景),使得 UI 页面的总体风格更加的美观和融洽。spa

好比,对于一些影视类的 App,视频详情页的主题都是视频的海报,那么对于页面背景,咱们能够提取视频海报的颜色,设置在背景上,使得效果更佳柔和美观。翻译

Palette 是一个 Support v7 的包,若是使用 Gradle 引入依赖,这里使用最新的 26.+。3d

compile "com.android.support:palette-v7:26.+"

2、Palette 的使用

Palette 使用起来很是的简单,既然目的是从一个图片中提取颜色,它的步骤就有:code

  1. 传递一个 Bitmap,获得一个 Palette。视频

  2. 经过 Palette 提取须要的颜色。

就是这么简单,如同要将大象放冰箱,须要几步同样清晰。

那么接下来咱们先来了解它使用的细节。

2.1 传递 Bitmap 获得一个 Palette

Palette 在旧版本上有一些 generate() 的方法,用于生成一个 Palette 对象,可是在新版本上已经被标记为 @Depercated 了,因此这里不推荐使用。

而在新版上,推荐使用 Palette.Builder 来建立咱们的 Palette 对象,咱们能够经过 from() 方法使用它。

/p-from.png

通常咱们使用第一个方法便可,直接传递进去一个 Bitmap 对象。获得 Builder 以后,咱们还能够配置一些规则,可是通常咱们不须要进行额外的(后面会讲到)。再经过 Builder.generate() 便可获得咱们须要的 Palette 对象了。

2.2 经过 Palette 提取颜色

Palette 从图片中提取的颜色,有不少选择。这里又涉及到另一个类,Swatch 。

Palette 可被提取的每一个颜色,都被封装成一个 Swatch 对象,用来管理多种颜色。

这些 Swatch 有:

  • DominantSwatch

  • VibrantSwatch

  • DarkVibrantSwatch

  • LightVibrantSwatch

  • MutedSwatch

  • DarkMutedSwatch

  • LightMutedSwatch

其实这些 Swatch,真的不太好解释其意义,惟一特别一点的就是 DominantSwatch ,它是从图片中提取的最突出的颜色。

这些 Swatch 在 Palette 都提供了对应的 getXxx() 方法得到。不过须要注意的是,这些 getXxx() 方法可能会获得一个 null ,由于有些颜色是没有的。

若是只是须要获得一个颜色值,Palette 同时也提供了对应的 getXxxColor() 方法,方便咱们使用。

获得 Swatch 对象以后,就能够经过对应的 Swatch 中对应的 Api 获取咱们须要的颜色值。

  • getPopulation() :Swatch 中的像素个数。

  • getRgb():颜色的 RGB 值。

  • getHsl():颜色的 HSL 值。

  • getBodyTextColor():对应的文字颜色值。

  • getTitleTextColor():对应的标题文字颜色值。

一般来讲,咱们只须要经过 getRgb() 获取到对应的颜色设置在背景上,若是背景之上还有文字内容,能够经过 getBodyTextColor() 提取出与背景匹配的文字颜色值,这样能够显得更加的柔和,让文字看起来更清晰和舒服。好比,若是一个深色的背景,为它设置一个默认的深色文字,基本上就看不见了,由于对比对太弱。

2.3 举个例子

到这里,基本上 Palette 的基本 Api 就讲解清楚了,下面举个实际的例子来看看。

这里找了三张 Eason 的海报,用于作 Palette 的 Demo 资源,间隔去替换图片,而后分别提取出对应的颜色和字体颜色,设置在下面按钮的背景上,而后每 3s 切换一张图片。

由于有一些图片,获取的 Swatch 可能会返回 null ,因此这里用了一个比价扎眼的红色,做为错误色。

如下是获取 Swatch 的代码。

/p-changeColor.png

接下来经过 Swatch 提取咱们须要的颜色。

/p-setViewColor.png

这里分别获取了须要的颜色以及字体颜色,下面看看运行的效果:

/p-run.gif

能够看到,确实有一些颜色,被标记成了红色,说明当前图片有获取不到的对应颜色。

3、分析 Palette 的实现

3.1 Palette 的主线逻辑

继续深刻看看 Palette 的实现原理,先从主线开始看。

Builder.generate() 开始。

/p-gen.jpg

从代码中能够看到,在 generate() 中,主线逻辑:

  1. 首先会经过 scaleBitmapDown() 方法,将图片压缩成一个小像素的,等于生成了一个新的 Bitmap 对象,这样有利于内存的管理,而且也减小了计算量。

  2. 而后再经过 mRegion 判断是否只是提取图片的某个区域,默认是完整的图片所有提取,固然也能够对 mRegion 进行配置。

  3. 以后再构造一个 ColorCutQuantizer 对象,使用它的 getQuantizedColors() 方法获得 Swatch。

  4. 使用完前面压缩的 Bitmap 对象以后,再使用 recycle() 将其回收掉。

  5. 最后,经过 Palette 自己的构造函数,去生成一个 Palette 对象,返回出去。

接下来看看比较关键的 ColorCutQuantizer 中的实现逻辑。

/p-quan.jpg

从代码中能够看到,其中的逻辑仍是很清晰的。

  1. 首先经过 quantizeFromRgb888() 方法,将每一个像素的颜色进行量化,相似于将每一个颜色取一个靠近的设置。举个不恰当的例子,将不一样深度的红,都标记成红色。

  2. 再经过 shouldIgnoreColor() 过滤掉不须要的颜色。

  3. 最终获取到的颜色,若是小于等于咱们设置的 maxColors,就能够经过 approximateToRgb888() 生成一批 Swatch。

  4. 若是大于 maxColors,就再经过 quantizePixels() 去掉一些杂色。

  5. 不管如何,最终操做的就是这里获得的 mQuantizedColors 对象。

3.2 Swatch 的 Target

全部须要的 Swatch ,都是被 Target 对象所标记。不一样的 Swatch 都是经过 Target 中标记的常量值,进行运算,获得行的颜色。

/p-target.png

3.3 过滤掉不须要的颜色

Palette 能够设置一些咱们不须要的颜色,让它们不参与运算。这里的过滤条件,经过 Filter 来设定,而且 Palette 也提供给了一个 DEFAULT_FALTER 来标记默认的过滤颜色。

/p-filter.png

能够看到,默认的 Filter 会过滤掉一些靠近黑和白的颜色。

固然,咱们也能够本身定义 Filter ,并经过 Palette 中的 addFilter()clearFilters() 来管理它。

/p-filtermethod.png

这里存储 Filter 的是一个 ArrayList ,因此咱们是能够定义不少个 Filter 加入进去的,它们都会生效。

3.4 设置 MaxColor

在 ColorCutQuantizer 中,被使用的 maxColor ,主要用于标记须要使用的颜色个数。它是能够经过 maximumColorCount() 方法,进行设置的,若是不对其进行设定,默认值为 16。

/p-maxcolor.png

理论上来讲,这里设置的maxColor 的值越大,运算花费的时间就越长。而越小,能够被选择的色值也就越少。

因此最佳的作法是根据当前 Bitmap 的用途来决定,色彩越丰富的图,设置的 maxColor 越大,便可。不过正常来讲也不须要额外的设定,默认的配置就挺好用了。

4、小结

到这里就分析完 Palette 的全部相关的内容,不要仅仅知足使用。实际上看了 Palette 的源码,对色彩的运算,也有了更加深刻的了解。

公众号二维码.jpg