使用 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

相關文章
相關標籤/搜索