Android自定義View實(shí)現(xiàn)顏色選取器
Android 自定義View 顏色選取器,可以實(shí)現(xiàn)水平、豎直選擇顏色類(lèi)似 SeekBar 的方式通過(guò)滑動(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 中使用:
<com.duan.colorpicker.ColorPickerView <!--替換包名--> android:layout_width="50dp" android:layout_height="200dp" app:indicatorEnable="true" app:indicatorColor="#fff" app:orientation="vertical" />
在 java 中使用:
... @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):類(lèi)似于 SeekBar 的滑塊,通過(guò)滑動(dòng)指示點(diǎn)來(lái)選取顏色
顏色條:放置可選顏色
顏色條通過(guò) Paint 的 setShader 方法,使用 LinearGradient 漸變色著色器繪制。
指示點(diǎn)只是普通的圓,不過(guò)加了陰影,使用 Paint 的 setShadowLayer 方法實(shí)現(xiàn),使用該方法時(shí)要關(guān)閉硬件加速。
2 實(shí)現(xiàn)邏輯
public class ColorPickerView extends View
控件繼承自 View。
2.1 onMeasure
onMeasure 方法完成控件大小的測(cè)量??丶x了最小寬高,所以當(dāng)指定控件寬高,且指定值小于最小寬高,則指定無(wú)效。
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)樗?,寬度小于高度時(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 份,兩份留白,這是高度的分配情況;顏色條的寬度滿(mǎn)足如下條件:在可用寬度的基礎(chǔ)上,左右分別留出指示點(diǎn)半徑的寬度,這是為了在指示點(diǎn)滑動(dòng)到左右端點(diǎn)時(shí)留出空間給指示點(diǎn)顯示,同時(shí)保證指示點(diǎn)圓心能完整的掃過(guò)整個(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)仍然有可能大部分遮擋甚至完全遮擋住顏色條,這種情況下并沒(méi)有進(jìn)行處理,此時(shí)只能由使用者進(jìn)行控制。經(jīng)過(guò)測(cè)試,在這種情況下(水平方向,寬大于高),當(dāng)寬高比大于 3 : 1 時(shí),顯示效果比較好,所以應(yīng)該盡量讓寬高比大于 3 : 1。豎直方向有同一的問(wèn)題,不同的是,此時(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)即可,無(wú)需再次生成指示點(diǎn)的位圖。
2.3 onDraw
onDraw 方法負(fù)責(zé)繪制,繪制時(shí)判斷指示點(diǎn)對(duì)應(yīng)位圖和顏色條對(duì)應(yīng)位圖是否需要重繪,需要?jiǎng)t重繪,后繪制兩張位圖到控件上,否則直接繪制兩張位圖到控件。
代碼中寫(xiě)了很多注釋?zhuān)梢詤⒄兆⑨尷斫狻?/p>
已上傳 Github,可以在這里找到:DuanJiaNing/ColorPicker
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android?RecyclerView實(shí)現(xiàn)九宮格效果
這篇文章主要為大家詳細(xì)介紹了Android?RecyclerView實(shí)現(xiàn)九宮格效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06Android 使用registerReceiver注冊(cè)BroadcastReceiver案例詳解
這篇文章主要介紹了Android 使用registerReceiver注冊(cè)BroadcastReceiver案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08完美解決EditText和ScrollView的滾動(dòng)沖突(上)
這篇文章主要為大家詳細(xì)介紹了完美解決EditText和ScrollView滾動(dòng)沖突的方法,感興趣的小伙伴們可以參考一下2016-06-06Emoji表情在Android JNI中的兼容性問(wèn)題詳解
這篇文章主要給大家介紹了關(guān)于Emoji表情在Android JNI中的兼容性問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Android JNI具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09淺談android組件化之ARouter簡(jiǎn)單使用
本篇文章主要介紹了淺談android組件化之ARouter簡(jiǎn)單使用,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09在Android項(xiàng)目中使用AspectJ的詳細(xì)攻詻
AspectJ是實(shí)現(xiàn)AOP的其中一款框架,內(nèi)部通過(guò)處理字節(jié)碼實(shí)現(xiàn)代碼注入,文章給大家提到AspectJ基礎(chǔ)語(yǔ)法和集成AspectJ的方式,對(duì)AspectJ在android中使用教程感興趣的朋友跟隨小編一起看看吧2021-06-06Eclipse開(kāi)發(fā)環(huán)境導(dǎo)入android sdk的sample中的源碼
初學(xué)Android編程,Android SDK中提供的Sample代碼自然是最好的學(xué)習(xí)材料,需要的朋友可以參考下2012-12-12Android編程實(shí)現(xiàn)在Activity中操作刷新另外一個(gè)Activity數(shù)據(jù)列表的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)在Activity中操作刷新另外一個(gè)Activity數(shù)據(jù)列表的方法,結(jié)合具體實(shí)例形式分析了2種常用的Activity交互實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-06-06