Android 自定義View 顏色選取器,可以實(shí)現(xiàn)水平、豎直選擇顏色類似 SeekBar 的方式通過滑動(dòng)選擇顏色。
效果圖
xml 屬性
1.indicatorColor 指示點(diǎn)顏色
2.indicatorEnable 是否使用指示點(diǎn)
3.orientation 方向
horizontal 水平
vertical 豎直
使用
復(fù)制 \library\src…\ColorPickerView.java 和 \library\src\main\res\values\attrs.xml 文件到你的項(xiàng)目中,就可以在使用啦。
示例:
在 xml 中使用:
1
2
3
4
5
6
|
< com.duan.colorpicker.ColorPickerView <!--替換包名--> android:layout_width="50dp" android:layout_height="200dp" app:indicatorEnable="true" app:indicatorColor="#fff" app:orientation="vertical" /> |
在 java 中使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
... @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); ColorPickerView picker = (ColorPickerView) findViewById(R.id.colorPickerView); picker.setIndicatorColor(Color.GREEN); picker.setOrientation(ColorPickerView.Orientation.HORIZONTAL); picker.setColors(Color.DKGRAY,Color.RED,Color.WHITE); picker.setOnColorPickerChangeListener( new ColorPickerView.OnColorPickerChangeListener() { @Override public void onColorChanged(ColorPickerView picker, int color) { // TODO } @Override public void onStartTrackingTouch(ColorPickerView picker) { // TODO } @Override public void onStopTrackingTouch(ColorPickerView picker) { // TODO } }); } ... |
實(shí)現(xiàn)解析
1 構(gòu)成
指示點(diǎn):類似于 SeekBar 的滑塊,通過滑動(dòng)指示點(diǎn)來選取顏色
顏色條:放置可選顏色
顏色條通過 Paint 的 setShader 方法,使用 LinearGradient 漸變色著色器繪制。
指示點(diǎn)只是普通的圓,不過加了陰影,使用 Paint 的 setShadowLayer 方法實(shí)現(xiàn),使用該方法時(shí)要關(guān)閉硬件加速。
2 實(shí)現(xiàn)邏輯
public class ColorPickerView extends View
控件繼承自 View。
2.1 onMeasure
onMeasure 方法完成控件大小的測(cè)量。控件定義了最小寬高,所以當(dāng)指定控件寬高,且指定值小于最小寬高,則指定無效。
2.2 onLayout
onLayout 方法比較關(guān)鍵,在該方法中需要完成如下的任務(wù):
1. 計(jì)算出控件可用空間
2. 初始化指示點(diǎn)的坐標(biāo)
3. 計(jì)算出顏色條的邊界
4. 設(shè)置顏色條的顏色(默認(rèn)的漸變色)
4. 初始化兩張 Bitmap(一張用于繪制顏色條,一張用于繪制指示點(diǎn))
2.2.1 指示點(diǎn)坐標(biāo)的確定:
初始化時(shí)默認(rèn)使指示點(diǎn)位于控件的中心,而后其位置由 onTouchEvent 方法控制,同時(shí)在 onTouchEvent 方法中進(jìn)行重繪通知以及當(dāng)前顏色選取。
2.2.2 顏色條邊界確定:
顏色條和指示點(diǎn)的大小比例計(jì)算方式:我將控件的可用空間(除去上下左右 padding 后剩余的空間)分為 9 份,這 9 份的分配方式是這樣的:
假設(shè)控件此時(shí)為水平方向,且寬度大于高度(這是一般的情況,在控件方向?yàn)樗剑瑢挾刃∮诟叨葧r(shí)的情況下,邊界要進(jìn)行特殊計(jì)算;控件方向?yàn)樨Q直,寬度大于高度的情況也需要特殊處理),取高度作為基數(shù)(取寬高中短的一邊作為基數(shù))進(jìn)行平均分配,即: 高度 / 9 = 每一份的大小。
1/9 留白
2/9 指示點(diǎn)在顏色條上方的部分
3/9 顏色條高度
2/9 指示點(diǎn)在顏色條下方的部分
1/9 留白
這樣分之后就可以得出 圓的直徑占有 9 份中的 7 份,顏色條占有 3 份,兩份留白,這是高度的分配情況;顏色條的寬度滿足如下條件:在可用寬度的基礎(chǔ)上,左右分別留出指示點(diǎn)半徑的寬度,這是為了在指示點(diǎn)滑動(dòng)到左右端點(diǎn)時(shí)留出空間給指示點(diǎn)顯示,同時(shí)保證指示點(diǎn)圓心能完整的掃過整個(gè)顏色條。豎直方向的測(cè)量計(jì)算邏輯也是一樣的。
特殊情況:
有兩種情況需要特殊處理
1. 控件為水平方向,此時(shí)控件的可用寬度小于可用高度。
2. 控件為豎直方向,此時(shí)控件的可用寬度大于可用高度。
這兩種情況的處理邏輯是一樣的,拿第一種情況舉例,若此時(shí)仍然以短邊(此時(shí)為寬)作為基數(shù)分為 9 份計(jì)算,左右分別留出圓半徑的寬度,此時(shí)圓直徑占有了控件可用寬的 7 / 9 ,而且顏色條左右分別留出 3.5 / 9(指示點(diǎn)半徑) 的空間,那么顏色條的寬度只剩 9 / 9 - ( 7 / 9) = 2/ 9 ,2 / 9 < 7 / 9,而且顏色條和指示點(diǎn)都是居中顯示的,這就導(dǎo)致指示點(diǎn)大部分遮擋甚至完全遮擋住顏色條。
解決方法:
針對(duì)第一種情況,此時(shí)使均分為 9 份的基數(shù)為寬(短邊)的 1 / 6(控件默認(rèn)有個(gè)最小寬高,默認(rèn)值的長(zhǎng)邊與短邊之比就是 6 : 1)。
第二種情況下,使基數(shù)為高度的 1 / 6。
不足:
假設(shè)控件為水平方向,此時(shí)控件的可用寬度大于可用高度,但寬與高差值很小。這種情況下,指示點(diǎn)仍然有可能大部分遮擋甚至完全遮擋住顏色條,這種情況下并沒有進(jìn)行處理,此時(shí)只能由使用者進(jìn)行控制。經(jīng)過測(cè)試,在這種情況下(水平方向,寬大于高),當(dāng)寬高比大于 3 : 1 時(shí),顯示效果比較好,所以應(yīng)該盡量讓寬高比大于 3 : 1。豎直方向有同一的問題,不同的是,此時(shí)應(yīng)盡量使高與寬的比值大于 3 : 1.
2.2.3 為什么使用兩張 Bitmap
onDraw 方法并不是直接繪制圓角矩形,然后繪制指示點(diǎn)(圓),這樣做會(huì)使兩部分直接繪制在一張位圖上,相互覆蓋,不利于取得當(dāng)前指示點(diǎn)所指顏色。因而使用兩張位圖,一張負(fù)責(zé)繪制顏色條,一張繪制指示點(diǎn),onDraw 時(shí)分別繪制這兩張位圖,取色時(shí)獲取顏色條對(duì)應(yīng)位圖上像素點(diǎn)的顏色即可。
取得位圖上指定點(diǎn)顏色的方法是使用 Bitmap 的 getPixel(int x,int y) 方法,這個(gè)方法可以取得位圖上由 x,y 指定的點(diǎn)像素,根據(jù)這個(gè)像素可以解析出這個(gè)點(diǎn)的顏色。
同時(shí)這樣可以提高控件繪制效率,在大多數(shù)情況下顏色條上的可選顏色是不會(huì)變化的,此時(shí)可以將在可選顏色發(fā)生變化后生成的位圖直接繪制到控件上,而不需要再一次繪制這個(gè)位圖,指示點(diǎn)也如此,只需在選取顏色時(shí)(滑動(dòng)指示點(diǎn)時(shí))改變繪制指示點(diǎn)位圖的坐標(biāo)即可,無需再次生成指示點(diǎn)的位圖。
2.3 onDraw
onDraw 方法負(fù)責(zé)繪制,繪制時(shí)判斷指示點(diǎn)對(duì)應(yīng)位圖和顏色條對(duì)應(yīng)位圖是否需要重繪,需要?jiǎng)t重繪,后繪制兩張位圖到控件上,否則直接繪制兩張位圖到控件。
代碼中寫了很多注釋,可以參照注釋理解。
已上傳 Github,可以在這里找到:DuanJiaNing/ColorPicker
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://blog.csdn.net/aimeimeiTS/article/details/77162143