本文為專項(xiàng)介紹Paint類
Paint 類
1.顏色
canvas 繪制內(nèi)容,有三層顏色處理
1.1基本顏色
Canvas的顏色填充方法:drawColor/drawRGB/drawARGB() ,直接將顏色值作為參數(shù)傳入臼婆。
drawBitmap() 填充bitmap的顏色,是有Bitmap對(duì)象來提供。
圖形和文字的顏色由Paint的參數(shù)來設(shè)置。
注: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);
注:在設(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è)值:
CLAMP:用彩色邊緣來填充多余空間
MIRROR:重復(fù)使用鏡像模式來的圖像來填充多余空間
REPEAT:重復(fù)圖像來填充多余空間
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);
構(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);
構(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);
實(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:
MIRROR:
REPAT:
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);
注:這里需要禁用硬件加速髓霞。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
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)圖像
Alpha合成
混合:也就是 Photoshop 等制圖軟件里都有的那些混合模式(multiply darken lighten 之類的)估蹄。這一類操作的是顏色本身而不是 Alpha 通道塑煎,并不屬于 Alpha 合成,所以和 Porter 與 Duff 這兩個(gè)人也沒什么關(guān)系元媚,不過為了使用的方便轧叽,它們同樣也被 Google 加進(jìn)了 PorterDuff.Mode 里。
由上圖可看出: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)像素相加:
一個(gè)「保持原樣」的「基本 LightingColorFilter 」麻昼,mul 為 0xffffff,add 為 0x000000(也就是0)馋辈,那么對(duì)于一個(gè)像素抚芦,它的計(jì)算過程就是:
基于這個(gè)「基本 LightingColorFilter 」,你就可以修改一下做出其他的 filter迈螟。比如叉抡,如果你想去掉原像素中的紅色,可以把它的 mul 改為 0x00ffff (紅色部分為 0 ) 井联,那么它的計(jì)算過程就是:
ColorFilter lightingColorFilter = new LightingColorFilter(0x00ffff, 0x000000);
paint.setColorFilter(lightingColorFilter);
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的矩陣秦驯。
通過計(jì)算,ColorMatrix 可以把要繪制的像素進(jìn)行轉(zhuǎn)換挣棕。對(duì)于顏色【R,G,B,A】译隘,轉(zhuǎn)換算法:
關(guān)于ColorMatrix,推薦StyleImageView
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)容的顏色處理方案词身。
例:
又是 PorterDuff.Mode 厅目。 PorterDuff.Mode 在 Paint 一共有三處 API ,它們的工作原理都一樣,只是用途不同:
注:Xfermode 只有一個(gè)子類(PorterDuffXfermode)损敷。
Xfermode 注意事項(xiàng)
1.使用離屏緩沖(Off-screen Buffer)
上面的代碼如果直接執(zhí)行不會(huì)繪制出圖中效果葫笼。程序在執(zhí)行的時(shí)候,也不會(huì)是上面的流程拗馒。
按照邏輯我們會(huì)認(rèn)為路星,在第二步畫圓的時(shí)候,跟它共同計(jì)算的是第一步繪制的方形瘟忱。但實(shí)際上奥额,卻是整個(gè) View 的顯示區(qū)域都在畫圓的時(shí)候參與計(jì)算,并且 View 自身的底色并不是默認(rèn)的透明色访诱,而且是遵循一種迷之邏輯,導(dǎo)致不僅繪制的是整個(gè)圓的范圍韩肝,而且在范圍之外都變成了黑色触菜。就像這樣:
要想使用setXfermode()正常繪制,必須使用離屏緩沖(Off-screen Buffer)把繪制的內(nèi)容繪制在額外的圖層上哀峻,再將繪制好的內(nèi)容貼回到View中涡相。
離屏緩沖的方式:
1.Canvas。saveLayer() saveLayer() 可以做短時(shí)的離屏緩沖
2.View.setLayerType() 是直接把整個(gè) View 都繪制在離屏緩沖中
setLayerType(LAYER_TYPE_HARDWARE) 是使用 GPU 來緩沖剩蟀, setLayerType(LAYER_TYPE_SOFTWARE) 是直接直接用一個(gè) Bitmap 來緩沖催蝗。
注:
如果沒有特殊需求,可以選用第一種方法 Canvas.saveLayer() 來設(shè)置離屏緩沖育特,以此來獲得更高的性能丙号。
2.控制好透明區(qū)域
如圖所示,由于透明區(qū)域過小而覆蓋不到的地方缰冤,將不會(huì)受到 Xfermode 的影響犬缨。
所以,我們?cè)谑褂肵fermode繪制內(nèi)容時(shí)候棉浸,除了注意離屏緩沖怀薛,還需要注意控制透明區(qū)域的大小,要讓他足夠覆蓋到要和他結(jié)合繪制的內(nèi)容迷郑。