1.前言今天给大家介绍一个Android下比较有意思的Supportv7库,Palette,翻译过来就是调色板。Palette可以从Bitmap中提取其突出的颜色,这样我们就可以在App的固定UI(例如:ToolBar的背景)中设置提取的颜色,使UI页面的整体风格更加美观和谐。比如一些影视app,视频详情页的主题是视频海报,那么对于页面背景,我们可以将视频海报的颜色提取出来,设置在背景上,让效果更加柔和美丽的。Palette是一个支持v7的包。如果使用Gradle引入依赖,这里使用最新的26.+。compile"com.android.support:palette-v7:26.+"2.使用PalettePalette使用起来非常简单。由于目的是从图片中提取颜色,因此其步骤如下:传递一个Bitmap并得到一个Palette。通过Palette提取需要的颜色。就这么简单,就像将大象放入冰箱需要多少步一样清楚。那我们先来了解一下它的使用细节。2.1通过Bitmap得到一个PalettePalette旧版本中有一些generate()方法可以生成一个Palette对象,但是在新版本中已经被标记为@Depercated,这里不推荐使用。在新版本中,推荐使用Palette.Builder来创建我们的Palette对象,我们可以通过from()方法来使用。一般我们可以使用第一种方式,直接传入一个Bitmap对象。拿到Builder之后,我们还可以配置一些规则,不过一般不需要额外做(后面会提到)。然后通过Builder.generate()我们就可以得到我们需要的Palette对象。2.2通过Palette提取颜色Palette有很多选项可以从图片中提取颜色。这里涉及到另一个类,Swatch。可以从Palette中提取的每种颜色都封装到一个Swatch对象中,以管理多种颜色。这些Swatches分别是:DominantSwatchVibrantSwatchDarkVibrantSwatchLightVibrantSwatchMutedSwatchDarkMutedSwatchLightMutedSwatch其实这些Swatches真的不好解释它们的含义。唯一特别的是DominantSwatch,它是从图片中提取的最突出的颜色。这些Swatches在Palette中提供了相应的getXxx()方法。但请注意,这些getXxx()方法可能会得到null,因为某些颜色不可用。如果只是需要获取一个颜色值,Palette也提供了对应的getXxxColor()方法方便我们使用。拿到Swatch对象后,我们就可以在对应的Swatch中通过对应的Api获取我们需要的颜色值。getPopulation():样本中的像素数。getRgb():颜色的RGB值。getHsl():颜色的HSL值。getBodyTextColor():对应的文字颜色值。getTitleTextColor():对应的标题文字颜色值。一般来说,我们只需要通过getRgb()得到对应的颜色,设置在背景上即可。如果背景上有文字内容,我们可以通过getBodyTextColor()提取与背景相匹配的文字颜色值,这样可以显得更柔和,让文字看起来更清晰、更舒服。比如你有一个深色的背景,如果你给它设置一个默认的深色文字,它基本上是看不见的,因为对比度太弱了。2.3举个例子到这里,基本上Palette的基本API都解释清楚了,下面来看一个实际的例子。这里找了三张Eason的海报,作为PaletteDemo资源,每隔一段时间更换图片,然后分别提取对应的颜色和字体颜色,设置在下方按钮的背景上,然后每隔3s切换一张图片。因为有一些图片,获取到的Swatch可能会返回null,所以这里我们使用醒目的红色作为错误颜色。下面是获取Swatch的代码。接下来通过Swatch提取我们需要的颜色。这里分别获取需要的颜色和字体颜色。看一下运行效果:可以看到确实有一些颜色被标记为红色,说明当前图片有对应的颜色无法获取。3、分析Palette的实现3.1Palette的主要逻辑继续深入看Palette的实现原理,从主线开始。从生成器开始。产生()。从代码可以看出,在generate()中,主要的逻辑是:首先通过scaleBitmapDown()方法将图片压缩成一个小像素,相当于生成了一个新的Bitmap对象,有利于内存管理也减少了计算量。然后用mRegion判断是否只提取图片的某个区域。默认是提取所有完整的图片。当然也可以配置mRegion。然后构造一个ColorCutQuantizer对象并使用它的getQuantizedColors()方法来获取Swatch。使用之前压缩过的Bitmap对象后,使用recycle()对其进行回收。***,使用Palette本身的构造函数生成一个Palette对象并返回。接下来我们来看比较关键的ColorCutQuantizer中的实现逻辑。从代码可以看出,逻辑还是很清晰的。首先,通过quantizeFromRgb888()方法对每个像素点的颜色进行量化,类似于对每种颜色取一个closesetting。举个不恰当的例子,将深浅不一的红色标记为红色。然后使用shouldIgnoreColor()过滤掉不需要的颜色。如果最终得到的颜色小于等于我们设置的maxColors,则可以通过approximateToRgb888()生成一批Swatches。如果它大于maxColors,则通过quantizePixels()去除一些噪声。不管怎样,最终操作的是这里得到的mQuantizedColors对象。3.2Swatch的Target所有需要的Swatches都由Target对象来标记。不同的Swatches通过Target中标注的常量值计算得到该行的颜色。3.3过滤掉不需要的颜色Palette可以设置一些不需要的颜色,让它们不参与计算。这里的过滤条件是通过Filter设置的,Palette也提供了一个DEFAULT_FALTER来标记默认的过滤颜色。可以看到默认的Filter会过滤掉一些接近黑白的颜色。当然,我们也可以自己定义Filter,通过Palette中的addFilter()和clearFilters()进行管理。这里,Filter是存储在一个ArrayList中的,所以我们可以定义很多Filter,添加进来,它们都会生效。3.4设置MaxColor在ColorCutQuantizer中,使用的maxColor主要用于标记要使用的颜色数。它可以通过maximumColorCount()方法进行设置。如果不设置,默认值为16。理论上,这里设置的maxColor值越大,运行时间越长。而且越小,可以选择的颜色值就越少。因此,最好的办法是根据当前Bitmap的用途来决定。地图颜色越丰富,您可以设置的maxColor越大。但通常不需要额外的设置,默认配置就非常好用。4.总结至此,我们已经分析完了Palette的所有相关内容,不仅仅是为了使用。其实看了Palette的源码,对颜色操作有了更深的理解。【本文为专栏作家“张扬”原创稿件,转载请微信♂联系作者获得授权】点此查看作者更多好文
