一翁锡、前言
ColorPicker桩了,顏色選取器附帽,簡稱拾色器。
說到拾色器井誉,大家可能就會(huì)想到Photoshop, 使用得最多的應(yīng)該是設(shè)計(jì)蕉扮, 對(duì)于開發(fā)而言,平常要用到拾色器的機(jī)會(huì)不多颗圣。
如果有一天喳钟,項(xiàng)目中需要一個(gè)拾色器(多用于自定義顏色),該如何入手在岂?
今天且來給大家分享一下拾色器的設(shè)計(jì)和實(shí)現(xiàn)奔则。
二、顏色空間
要實(shí)現(xiàn)實(shí)用的拾色器蔽午,了解下顏色空間是必要的易茬。
顏色空間也稱彩色模型(又稱彩色空間或彩色系統(tǒng)),它的用途是在某些標(biāo)準(zhǔn)下用通常可接受的方式對(duì)彩色加以說明擦盾。
關(guān)于顏色空間,文末附有一些鏈接又碌,都是前人的精華總結(jié)岸蜗。
尤其是《色彩空間中的 HSL尉咕、HSV、HSB 有什么區(qū)別》中的討論(知乎大神的作答)璃岳,讀完立即醍醐灌頂年缎,茅塞頓開。
本節(jié)主要摘錄各大神的一些表述铃慷,并加以整理单芜。
為了閱讀體驗(yàn),就不逐一附上作者了犁柜,具體見文后鏈接洲鸠。
2.1 RGB空間
RGB是從顏色發(fā)光的原理來設(shè)計(jì)定的,通俗點(diǎn)說它的顏色混合方式就好像有紅馋缅、綠扒腕、藍(lán)三盞燈,當(dāng)它們的光相互疊合的時(shí)候萤悴,色彩相混瘾腰,而亮度卻等于兩者亮度之總和,越混合亮度越高覆履,即加法混合蹋盆。
紅、綠硝全、藍(lán)三個(gè)顏色通道每種色各分為256階亮度栖雾,在0時(shí)“燈”最弱——是關(guān)掉的,而在255時(shí)“燈”最亮伟众。
當(dāng)三色灰度數(shù)值相同時(shí)析藕,產(chǎn)生不同灰度值的灰色調(diào),即三色灰度都為0時(shí)赂鲤,是最暗的黑色調(diào)噪径;三色灰度都為255時(shí),是最亮的白色調(diào)数初。
2.2 HSB空間
RGB 是對(duì)機(jī)器很友好的色彩模式找爱,但并不夠人性化,因?yàn)槲覀儗?duì)色彩的認(rèn)識(shí)往往是”什么顏色泡孩?鮮艷不鮮艷车摄?亮還是暗?”。
例如吮播,我們平時(shí)描述顏色变屁,“深紫”,“淺綠”意狠,“明黃”粟关,"暗紅”等,一是交代基礎(chǔ)顏色环戈,二是對(duì)顏色本身加以描述闷板。
HSB(HSV) 基于 RGB ,是一個(gè)更人性化的表示方法院塞。
H(Hue) 為色相, 取值范圍:0-360°遮晚,基礎(chǔ)顏色。
S(Saturation) 為飽和度拦止, 取值范圍:0 - 1(0% - 100%), 表示色彩的純度县遣。
B(Brightness)為明度, 取值范圍:0 - 1(0% - 100%),表示對(duì)光量的感知汹族。
明度在某些地方也叫Value萧求,所以就有了HSV,HSV和HSB是一樣的鞠抑,只是關(guān)于明度的叫法不一樣而已饭聚。
- 色相環(huán)的每一種顏色忌警,在RGB空間中搁拙,最多只有兩個(gè)顏色通道(r, g, b)大于0,所以色相環(huán)的顏色是最純凈的法绵。
- 明度決定了RBG三個(gè)分量的大小箕速,也就是決定了光亮的大小,在感知層面朋譬,就是明暗的區(qū)別盐茎。
- 飽和度為0的顏色,r徙赢,g字柠,b相等, 當(dāng)明度為0時(shí)為黑色,明度為1時(shí)為白色狡赐,大于0小于1時(shí)為灰色窑业;
飽和度為1時(shí),顏色值僅取決于色相和明度枕屉,而明度只控制RGB分量的大小常柄,所以顏色還是純凈的;
飽和度在0到1之間時(shí),為飽和度為0的顏色(黑灰白)和飽和度為1的顏色的線性插值西潘,越靠近1顏色越純凈卷玉。
2.3 明度
先看 Photoshop 的 HSB 顏色模型拾色器,如下圖所示喷市,HSB 的 B(明度)控制純色中混入黑色的量相种,越往上,值越大品姓,黑色越少蚂子,顏色明度越高缭黔。
2.4 飽和度
如下圖所示食茎,HSB 的 S(飽和度)控制純色中混入白色的量,越往右馏谨,值越大别渔,白色越少,顏色純度越高惧互。
2.5 色相
色相指的是色彩的外相哎媚,是在不同波長的光照射下,人眼所感覺不同的顏色喊儡,如紅色拨与、黃色、藍(lán)色等艾猜。
在HSL和HSV色彩空間中买喧,H指的就是色相,是以紅色為0°(360°)匆赃;黃色為60°淤毛;綠色為120°;青色為180°算柳;藍(lán)色為240°低淡;品紅色為300°。
從上圖可以看出瞬项,從0°到360°蔗蹋,是一個(gè)分段函數(shù),其中囱淋,每一段都有一個(gè)顏色分量是0猪杭,一個(gè)分量是1,另一個(gè)分量或從0到1绎橘,或從1到0胁孙。
2.6 HSB轉(zhuǎn)RGB
對(duì)用戶而言唠倦,HSB空間更容易調(diào)節(jié),但是對(duì)于計(jì)算機(jī)涮较,用RGB空間渲染會(huì)更加方便稠鼻。
以下是HSB到RGB的轉(zhuǎn)換公式:
圖中, h, s , v分別是色相,飽和度狂票,明度候齿。
有了這個(gè)組公式,我們就可以理解2.5節(jié)的色相條是怎么來的了闺属。
首先看到第一個(gè)公式慌盯,[]是取整符號(hào),即 hi = (int) (h/60)% 6 掂器。
令s=1, v=1, 則p=0, q=1-f, t=f亚皂。
當(dāng)i=0(第一段),(r, g, b) = (v, t, p) = (1, f, 0), 而f=h/60-hi =h/60国瓮,
也就是灭必,第一段中,r=1, g=h/60, b=0乃摹;
特例:當(dāng)h=60禁漓, r=1,g=1,b=0, 混合出黃色。
以此類推孵睬。
另外我們還注意到播歼,當(dāng)h選定之后,顏色和s掰读,v成線性關(guān)系秘狞,這一點(diǎn)對(duì)后面拾色器的實(shí)現(xiàn)很重要。
三磷支、拾色器的設(shè)計(jì)
3.1 條形拾色器
需要用到自定義顏色的APP不多谒撼,網(wǎng)易APP是其中一個(gè)食寡。
點(diǎn)擊“個(gè)性換膚->自選顏色”雾狈,會(huì)彈出這樣的界面:
頁面中間是預(yù)覽,底部是預(yù)定義的調(diào)色板抵皱;
調(diào)色板的最后善榛,是一張多彩的圖片,點(diǎn)擊后切換成兩個(gè)顏色條呻畸,如下圖:
第一個(gè)顏色條很眼熟了移盆,就是前面提到的色相;
底下這條伤为,應(yīng)該是以選取的色相為基礎(chǔ)咒循,飽和度為1据途,明度從0到1漸變。
這兩個(gè)顏色條組合起來叙甸,顏色的取值范圍為2.2節(jié)中的圓柱的側(cè)面颖医。
取值范圍雖然只占顏色空間的一部分,但是也是很有價(jià)值的一部分裆蒸。
可能網(wǎng)易的設(shè)計(jì)師只想讓用戶選取鮮明的顏色熔萧,所以舍棄了飽和度的調(diào)節(jié),同時(shí)換來了極大的簡潔性僚祷。
3.2 環(huán)形拾色器
開源的Android拾色器有不少佛致,其中HoloColorPicker是star比較多的一個(gè)項(xiàng)目。
該項(xiàng)目把色相做成一個(gè)環(huán)辙谜,底下輔以飽和度和明度的調(diào)節(jié)俺榆,可以說是一個(gè)完整的拾色器了(可以選取整個(gè)顏色空間的顏色)。
把色相做成色相環(huán)装哆,看起來比色相條要更加炫酷一些肋演,但是占用面積變大了。
像網(wǎng)易云音樂的顏色選取烂琴,因?yàn)橐o預(yù)覽圖足夠的空間爹殊,所以只能用空間占用少的拾色器;
像這種一下占用大半個(gè)屏幕的設(shè)計(jì)奸绷,不適合網(wǎng)易云音樂這種選色場(chǎng)景梗夸。
3.3 PS拾色器
Photoshop的常規(guī)拾色器是矩形構(gòu)成的“飽和度-明度”選取面板,以及色相條(然后也可以通過設(shè)置換成色相輪)号醉。
Photoshop作為專業(yè)的圖像編輯軟件反症,拾色器無疑是很強(qiáng)大的。
同時(shí)電腦顯示器的面積畢竟比手機(jī)要大很多畔派,鼠標(biāo)的選取精確度也比手指觸摸屏幕要精確铅碍,
所以Photoshop的拾色器可以大開大合,提供各種面板线椰,顯示全面的參數(shù)胞谈。
四、技術(shù)實(shí)現(xiàn)
通過前面三個(gè)小節(jié)的分析憨愉,我們可以看出烦绳,拾色器的實(shí)現(xiàn)要點(diǎn)為:
以HSB顏色空間為基礎(chǔ),通過條形配紫,環(huán)形径密,矩形等坐標(biāo)來調(diào)節(jié)HSB各分量的值,達(dá)成顏色的選取躺孝。
首先第一個(gè)要解決的問題就是享扔,顏色空間的轉(zhuǎn)換計(jì)算底桂。
幸運(yùn)的是,SDK 的 Color 類提供HSB(HSV)和RGB之間的轉(zhuǎn)換方法:
public static void colorToHSV(@ColorInt int color, @Size(3) float hsv[])
public static int HSVToColor(@Size(3) float hsv[])
然后要解決的第二個(gè)問題是惧眠,坐標(biāo)的繪制戚啥。
同樣,SDK也提供了各種Shader, 使得我們可以輕松的繪制各種坐標(biāo)锉试。
接下來我們結(jié)合實(shí)例看一下猫十。
4.1 仿網(wǎng)易云音樂
也不賣關(guān)子了,先上效果圖吧:
和網(wǎng)易云音樂一樣呆盖,都是在下方顯示面板拖云,有預(yù)置的調(diào)色板,調(diào)色板最后的方塊可以跳轉(zhuǎn)去自定義暗色应又;
不同之處在于宙项,比之多了透明度和純度的調(diào)節(jié),如此株扛,可以選擇整個(gè)顏色空間尤筐,以及alpha通道。
以上實(shí)現(xiàn)的關(guān)鍵點(diǎn)在于洞就,色相盆繁、飽和度(為了字體長度相同,以“純度”作為title)旬蟋,以及明度的繪制油昂。
前面我們提到,色相是分段線性變化的倾贰,因此冕碟,我們可以利用 LinearGradient 來繪制。
public LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int colors[],
@Nullable float positions[], @NonNull TileMode tile)
給LinearGradient的color數(shù)組福祉匆浙,只需列出色相在分段交界的顏色即可:
private static final int[] COLORS = new int[] {
0xFFFF0000,
0xFFFFFF00,
0xFF00FF00,
0xFF00FFFF,
0xFF0000FF,
0xFFFF00FF,
0xFFFF0000,
};
前面2.6節(jié)提到安寺,h確定之后, 顏色和s,v成線性關(guān)系首尼,因此挑庶,也可以通過LinearGradient來繪制飽和度和明度。
例如饰恕,繪制飽和度時(shí)挠羔,只需計(jì)算hsv第二分量(hsv[1], 也就是s)等于0和等于1時(shí)的顏色值,作為LinearGradient的colors的參數(shù)埋嵌,即可繪制在當(dāng)前h, v值對(duì)應(yīng)的s的變化(也就是飽和度對(duì)應(yīng)的顏色條)。
hsv[1] = 0f;
colors[0] = Color.HSVToColor(hsv);
hsv[1] = 1f;
colors[1] = Color.HSVToColor(hsv);
明度的繪制以此類推俱恶。
4.2 仿Photoshop
色相在0°和360°對(duì)應(yīng)的都是紅色雹嗦,首位相接范舀,所以很多時(shí)候會(huì)被做成色相環(huán)(Photoshop中叫色相輪)。
飽和度和明度了罪,如果合成一個(gè)二維坐標(biāo)锭环,會(huì)更加直觀,這樣也是Photoshop的方案泊藕。
要繪制色相環(huán)辅辩,需要用到另一個(gè)Shader:
public SweepGradient(float cx, float cy,
@NonNull @ColorInt int colors[], @Nullable float positions[])
用法很簡單,把上一節(jié)給出的 COLORS 代入 SweepGradient 的 colors 即可娃圆。
而要合成飽和度和明度玫锋,可以用ComposeShader:
private Shader getSVShader() {
if (mValShader == null) {
mValShader = new LinearGradient(
mSVRect.left, mSVRect.top,
mSVRect.left, mSVRect.bottom,
Color.WHITE, Color.BLACK, Shader.TileMode.CLAMP);
}
if (mShaderHSV[0] != mHSV[0] || mComposeShader == null) {
mShaderHSV[0] = mHSV[0];
Shader satShader = new LinearGradient(
mSVRect.left, mSVRect.top,
mSVRect.right, mSVRect.top,
Color.WHITE, Color.HSVToColor(mShaderHSV), Shader.TileMode.CLAMP);
mComposeShader = new ComposeShader(mValShader, satShader, PorterDuff.Mode.MULTIPLY);
}
return mComposeShader;
}
ComposeShader可以組合兩個(gè)Shader, 因?yàn)轭伾蛃, v是線性關(guān)系,所以需要組合兩個(gè)LinearGradient讼呢。
第一個(gè)LinearGradient從左上角到左下角撩鹿,從白到黑;
第二個(gè)LinearGradient從左上角到右上角悦屏,從白到色相的顏色节沦。
效果如下:
既然拾色部分已經(jīng)占了這么多空間了,所以干脆把剩下的空間也用上础爬,來做數(shù)據(jù)面板甫贯;
還加一個(gè)編輯框,可以手動(dòng)輸入RGB顏色看蚜,同時(shí)限制編輯框只能輸入十六進(jìn)制获搏,限制輸入長度。
五失乾、總結(jié)
兩類拾色器中常熙,通過條形坐標(biāo)來選取顏色比較節(jié)約空間,通過環(huán)形和矩形則相對(duì)直觀碱茁。
具體使用哪一種裸卫,要視情況而定:
如果要實(shí)時(shí)預(yù)覽效果,那拾色器就不能占太多空間纽竣,這時(shí)候第一種方案會(huì)比較適合墓贿;
如果要制作調(diào)色板之類的,用第二種方案就比較高效蜓氨。
限于篇幅聋袋,在實(shí)現(xiàn)方面沒有講的很細(xì),讀者可以具體看項(xiàng)目代碼穴吹。
代碼鏈接:
https://github.com/No89757/ColorPicker
參考資料:
色彩空間中的 HSL幽勒、HSV、HSB 有什么區(qū)別
從 RGB 到 HSV 的轉(zhuǎn)換詳細(xì)介紹
RGB與HSB之間的轉(zhuǎn)換公式
維基百科 - 色相