自定義View Paint 詳解-1

本文為專項(xiàng)介紹Paint類

Paint 類

image.png

1.顏色

canvas 繪制內(nèi)容,有三層顏色處理
image.png

1.1基本顏色

Canvas的顏色填充方法:drawColor/drawRGB/drawARGB() ,直接將顏色值作為參數(shù)傳入臼婆。
drawBitmap() 填充bitmap的顏色,是有Bitmap對(duì)象來提供。
圖形和文字的顏色由Paint的參數(shù)來設(shè)置。


image.png

注:Paint設(shè)置顏色的兩種方式:
1.Paint.setColor/ARGB()來設(shè)置顏色署鸡。
2.通過設(shè)置Shader(調(diào)色板)來設(shè)置顏色方案。

1.1.1 直接設(shè)置顏色

--paint.setColor(Color.RED);
--paint.setColor(Color.parseColor("#003000"));
--paint.setARGB(int a,int b,int g,int b)

1.1.2 設(shè)置Shader

介紹 Shader : Shader 為著色器限嫌,用于設(shè)置繪制有顏色靴庆。他是圖形領(lǐng)域通用的概念。他與直接設(shè)置顏色不同的是怒医,著色器設(shè)置的是一個(gè)顏色方案炉抒。

在Android中,Shader的子類:LinearGradient RadialGradient SweepGradient BitmapShader ComposeShader

1.1.2.1 LinearGradient 線性漸變

先設(shè)置兩個(gè)點(diǎn)稚叹,然后有以這兩個(gè)點(diǎn)為斷電焰薄,使用兩種顏色的漸變來繪制
例:

Shadershader=newLinearGradient(100,100,500,500,Color.parseColor("#E91E63"),Color.parseColor("#2196F3"),Shader.TileMode.CLAMP);

canvas.drawRect(100,100,500,500,paint);


image.png

注:在設(shè)置Shader后,Paint.setColor/ARGB() 所設(shè)置的顏色就不會(huì)再起作用扒袖。

構(gòu)造方法:

LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile)
參數(shù):
        --x0,y0  x1,y1:漸變的兩個(gè)端點(diǎn)的位置塞茅。
        --color0,color1:端點(diǎn)的顏色季率。
        --title 端點(diǎn)范圍之外的著色規(guī)則野瘦。

TileMode 是個(gè)枚舉類,共三個(gè)值:


image.png
CLAMP:用彩色邊緣來填充多余空間
image.png
MIRROR:重復(fù)使用鏡像模式來的圖像來填充多余空間
image.png
REPEAT:重復(fù)圖像來填充多余空間
image.png
1.1.2.2 RadialGradient 輻射漸變

從中心來向四周輻射
例:

Shadersharder=newRadialGradient(300,300,200,Color.parseColor("#E91E63"),Color.parseColor("#2196F3"),Shader.TileMode.CLAMP);

canvas.drawCircle(300,300,200,paint);


image.png
構(gòu)造方法:
RadialGradient(float centerX, float centerY, float radius, int centerColor, int edgeColor, TileMode tileMode)飒泻。
        參數(shù):
        centerX centerY:輻射中心的坐標(biāo) 
        radius:輻射半徑 
        centerColor:輻射中心的顏色 
        edgeColor:輻射邊緣的顏色 
        tileMode:輻射范圍之外的著色模式缅刽。
1.1.2.3 SweepGradient 掃描漸變

類似與雷達(dá)掃描
例:

  Shadershader=newSweepGradient(300,300,Color.parseColor("#E91E63"),Color.parseColor("#2196F3"));

canvas.drawCircle(300,300,200,paint);


image.png

構(gòu)造方法
SweepGradient(float cx, float cy, int color0, int color1)
參數(shù):
cx cy :掃描的中心
color0:掃描的起始顏色
color1:掃描的終止顏色

1.1.2.4 BitmapShader

用Bitmap 的像素來作為圖形或者文字的填充啊掏。
例:

Bitmapbitmap=BitmapFactory.decodeResource(getResources(),R.drawable.what_the_fuck);
Shadershader=newBitmapShader(bitmap,Shader.TileMode.CLAMP,Shader.TileMode.CLAMP);
canvas.drawCircle(200,200,200,paint);
image.png
image.png

實(shí)際上他與 Canvas.drawBitmap()效果類似蠢络。
繪制圓形Bitmap衰猛,就可以使用drawCircle() + BitmapShader()

構(gòu)造方法:

BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)
        參數(shù): 
        bitmap:用來做模板的 Bitmap 對(duì)象 
        tileX:橫向的 TileMode 
        tileY:縱向的 TileMode。
        
        注:這里的title刹孔,需要設(shè)置縱向跟橫向的啡省。
CLAMP:
image.png
MIRROR:
image.png
REPAT:
image.png
1.1.2.5 ComposeShader 混合著色器

簡(jiǎn)而言之:將兩個(gè)Shader 一起用。
例:

setLayerType(LAYER_TYPE_SOFTWARE,null);

Bitmapbitmap=BitmapFactory.decodeResource(getResources(),R.drawable.what_the_fuck);
Shadershader=newBitmapShader(bitmap,Shader.TileMode.CLAMP,Shader.TileMode.CLAMP);
        
Bitmapbitmap1=BitmapFactory.decodeResource(getResources(),R.drawable.batman_logo);
Shadershader1=newBitmapShader(bitmap1,Shader.TileMode.CLAMP,Shader.TileMode.CLAMP);
        
Shadershader2=newComposeShader(shader,shader1,PorterDuff.Mode.DST_IN);
        
paint.setShader(shader2);
image.png
注:這里需要禁用硬件加速髓霞。ComposeShader() 在硬件加速條件下不支持兩個(gè)同類型的Shader卦睹。

構(gòu)造方法:

ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)
        參數(shù): 
        shaderA, shaderB:兩個(gè)相繼使用的 Shader 
        mode: 兩個(gè) Shader 的疊加模式,即 shaderA 和 shaderB 應(yīng)該怎樣共同繪制方库。它的類型是PorterDuff.Mode 
PorterDuff.Mode
image.png

ProterDuff.Mode是一個(gè)枚舉類结序,他是用來指定兩個(gè)圖像共有繪制時(shí)的顏色策略。他通過不同mode類型類指定不同的策略纵潦。(簡(jiǎn)單的說徐鹤,就是兩個(gè)圖形,指定他們以什么樣的方式合并成一個(gè)圖形)

PorterDuff.Mode 共有17個(gè)類型邀层,分為兩類
1.Alpha 合成  12種類
2.混合(Blending)

Alpha 合成:其實(shí)就是 「PorterDuff」 這個(gè)詞所指代的算法返敬。 「PorterDuff」 并不是一個(gè)具有實(shí)際意義的詞組,而是兩個(gè)人的名字(準(zhǔn)確講是姓)寥院。這兩個(gè)人當(dāng)年共同發(fā)表了一篇論文劲赠,描述了 12 種將兩個(gè)圖像共同繪制的操作(即算法)。而這篇論文所論述的操作秸谢,都是關(guān)于 Alpha 通道(也就是我們通俗理解的「透明度」)的計(jì)算的凛澎,后來人們就把這類計(jì)算稱為Alpha 合成 ( Alpha Compositing ) 。

Google 官方效果
源圖像和目標(biāo)圖像


image.png
Alpha合成
image.png

混合:也就是 Photoshop 等制圖軟件里都有的那些混合模式(multiply darken lighten 之類的)估蹄。這一類操作的是顏色本身而不是 Alpha 通道塑煎,并不屬于 Alpha 合成,所以和 Porter 與 Duff 這兩個(gè)人也沒什么關(guān)系元媚,不過為了使用的方便轧叽,它們同樣也被 Google 加進(jìn)了 PorterDuff.Mode 里。


image.png

由上圖可看出:Alpha合成類的效果直觀刊棕,混合類的效果比較抽象炭晒。當(dāng)我們掌握了Alpha類的合成,記住混合類的名字甥角,當(dāng)我們?cè)倏吹綇?fù)雜UI的設(shè)計(jì)圖的時(shí)候网严,自己馬上就能知道能不能做,怎么做了嗤无。

1.2 setColorFilter(ColorFilter colorFilter)

ColorFilter類:為繪制設(shè)置顏色過濾(就是為繪制的內(nèi)容設(shè)置一個(gè)統(tǒng)一的過濾策略震束,然后Canvas.drawXXX()方法對(duì)每個(gè)像素都進(jìn)行過濾后再繪制出來)怜庸。

在 Paint 里設(shè)置 ColorFilter ,使用的是 Paint.setColorFilter(ColorFilter filter) 方法垢村。 ColorFilter 并不直接使用割疾,而是使用它的子類。它共有三個(gè)子類:LightingColorFilter PorterDuffColorFilter 和 ColorMatrixColorFilter嘉栓。

1.2.1 LightingColorFilter(模擬簡(jiǎn)單的光照效果)

LightingColorFilter 的構(gòu)造方法是 LightingColorFilter(int mul, int add) 宏榕,參數(shù)里的 mul 和 add 都是和顏色值格式相同的 int 值,其中 mul 用來和目標(biāo)像素相乘侵佃,add 用來和目標(biāo)像素相加:


image.png

一個(gè)「保持原樣」的「基本 LightingColorFilter 」麻昼,mul 為 0xffffff,add 為 0x000000(也就是0)馋辈,那么對(duì)于一個(gè)像素抚芦,它的計(jì)算過程就是:

image.png

基于這個(gè)「基本 LightingColorFilter 」,你就可以修改一下做出其他的 filter迈螟。比如叉抡,如果你想去掉原像素中的紅色,可以把它的 mul 改為 0x00ffff (紅色部分為 0 ) 井联,那么它的計(jì)算過程就是:


image.png

ColorFilter lightingColorFilter = new LightingColorFilter(0x00ffff, 0x000000);
paint.setColorFilter(lightingColorFilter);

image.png

1.2.2 PorterDuffColorFilter

PorterDuffColorFilter 他的作用是使用一個(gè)指定的顏色和一種指定的PorterDuff.Mode來與繪制對(duì)象進(jìn)行合成卜壕。

構(gòu)造方法:

PorterDuffColorFilter(int color, PorterDuff.Mode mode)
    參數(shù):
    color 參數(shù)是指定的顏色
    mode 參數(shù)是指定的 Mode。同樣也是 PorterDuff.Mode 烙常,不過和 ComposeShader 不同的是轴捎,PorterDuffColorFilter 作為一個(gè) ColorFilter,只能指定一種顏色作為源蚕脏,而不是一個(gè) Bitmap侦副。
1.2.3 ColorMatrixColorFilter

ColorMatrixColorFilter 他是使用一個(gè)ColorMatrix來對(duì)顏色進(jìn)行處理。ColorMatrix類驼鞭,他的內(nèi)部是一個(gè)4*5的矩陣秦驯。


image.png

通過計(jì)算,ColorMatrix 可以把要繪制的像素進(jìn)行轉(zhuǎn)換挣棕。對(duì)于顏色【R,G,B,A】译隘,轉(zhuǎn)換算法:


image.png

關(guān)于ColorMatrix,推薦StyleImageView
image.png

1.3 setXfermode(Xfermode xfermode)

Xfermode 指的是你要繪制的內(nèi)容和 Canvas 的目標(biāo)位置的內(nèi)容應(yīng)該怎樣結(jié)合計(jì)算出最終的顏色洛心。
其實(shí)就是將你要繪制的內(nèi)容作為源圖像固耘,以View中已有的內(nèi)容作為目標(biāo)圖像,選取一個(gè)PorterDuffer.Mode繪制內(nèi)容的顏色處理方案词身。
例:


image.png

image.png

image.png

又是 PorterDuff.Mode 厅目。 PorterDuff.Mode 在 Paint 一共有三處 API ,它們的工作原理都一樣,只是用途不同:


image.png
注:Xfermode 只有一個(gè)子類(PorterDuffXfermode)损敷。
Xfermode 注意事項(xiàng)
1.使用離屏緩沖(Off-screen Buffer)

上面的代碼如果直接執(zhí)行不會(huì)繪制出圖中效果葫笼。程序在執(zhí)行的時(shí)候,也不會(huì)是上面的流程拗馒。


image.png

按照邏輯我們會(huì)認(rèn)為路星,在第二步畫圓的時(shí)候,跟它共同計(jì)算的是第一步繪制的方形瘟忱。但實(shí)際上奥额,卻是整個(gè) View 的顯示區(qū)域都在畫圓的時(shí)候參與計(jì)算,并且 View 自身的底色并不是默認(rèn)的透明色访诱,而且是遵循一種迷之邏輯,導(dǎo)致不僅繪制的是整個(gè)圓的范圍韩肝,而且在范圍之外都變成了黑色触菜。就像這樣:


image.png

要想使用setXfermode()正常繪制,必須使用離屏緩沖(Off-screen Buffer)把繪制的內(nèi)容繪制在額外的圖層上哀峻,再將繪制好的內(nèi)容貼回到View中涡相。


image.png

離屏緩沖的方式:
1.Canvas。saveLayer() saveLayer() 可以做短時(shí)的離屏緩沖


image.png

2.View.setLayerType() 是直接把整個(gè) View 都繪制在離屏緩沖中
setLayerType(LAYER_TYPE_HARDWARE) 是使用 GPU 來緩沖剩蟀, setLayerType(LAYER_TYPE_SOFTWARE) 是直接直接用一個(gè) Bitmap 來緩沖催蝗。

注:
如果沒有特殊需求,可以選用第一種方法 Canvas.saveLayer() 來設(shè)置離屏緩沖育特,以此來獲得更高的性能丙号。

2.控制好透明區(qū)域


image.png

如圖所示,由于透明區(qū)域過小而覆蓋不到的地方缰冤,將不會(huì)受到 Xfermode 的影響犬缨。
所以,我們?cè)谑褂肵fermode繪制內(nèi)容時(shí)候棉浸,除了注意離屏緩沖怀薛,還需要注意控制透明區(qū)域的大小,要讓他足夠覆蓋到要和他結(jié)合繪制的內(nèi)容迷郑。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末枝恋,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子嗡害,更是在濱河造成了極大的恐慌焚碌,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件就漾,死亡現(xiàn)場(chǎng)離奇詭異呐能,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門摆出,熙熙樓的掌柜王于貴愁眉苦臉地迎上來朗徊,“玉大人,你說我怎么就攤上這事偎漫∫遥” “怎么了?”我有些...
    開封第一講書人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵象踊,是天一觀的道長(zhǎng)温亲。 經(jīng)常有香客問我,道長(zhǎng)杯矩,這世上最難降的妖魔是什么栈虚? 我笑而不...
    開封第一講書人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮史隆,結(jié)果婚禮上魂务,老公的妹妹穿的比我還像新娘。我一直安慰自己泌射,他們只是感情好粘姜,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著熔酷,像睡著了一般孤紧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拒秘,一...
    開封第一講書人閱讀 52,457評(píng)論 1 311
  • 那天号显,我揣著相機(jī)與錄音,去河邊找鬼翼抠。 笑死咙轩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的阴颖。 我是一名探鬼主播活喊,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼量愧!你這毒婦竟也來了钾菊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤偎肃,失蹤者是張志新(化名)和其女友劉穎煞烫,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體累颂,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡滞详,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年凛俱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片料饥。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蒲犬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出岸啡,到底是詐尸還是另有隱情原叮,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布巡蘸,位于F島的核電站奋隶,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏悦荒。R本人自食惡果不足惜唯欣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望逾冬。 院中可真熱鬧黍聂,春花似錦、人聲如沸身腻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)嘀趟。三九已至,卻和暖如春愈诚,著一層夾襖步出監(jiān)牢的瞬間她按,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工炕柔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留酌泰,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓匕累,卻偏偏與公主長(zhǎng)得像陵刹,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子欢嘿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

推薦閱讀更多精彩內(nèi)容