Paint 詳解
Paint 的 API 大致可以分為 4 類:
- 顏色
- 效果
- drawText() 相關
- 初始化
1 顏色
Canvas 繪制的內(nèi)容豆同,有三層對顏色的處理:
1.1 基本顏色
- 像素的基本顏色,根據(jù)繪制內(nèi)容的不同而有不同的控制方式: Canvas 的顏色填充類方法 drawColor/RGB/ARGB() 的顏色,是直接寫在方法的參數(shù)里,通過參數(shù)來設置的;
- drawBitmap() 的顏色份名,是直接由 Bitmap 對象來提供的;
- 圖形和文字的繪制妓美,它們的顏色就需要使用 paint 參數(shù)來額外設置(drawCircle() / drawPath() / drawText() ...)僵腺。
Paint 設置顏色的方法有兩種:
- 一種是直接用 Paint.setColor/ARGB() 來設置顏色;
- 另一種是使用 Shader 來指定著色方案。
1.1.1 直接設置顏色
1.1.1.1 setColor(int color)
paint.setColor(Color.parseColor("#000000"))
canvas.drawRect(left, top, right, bottom, paint)
paint.setColor(Color.parseColor("#90909009"))
canvas.drawLine(left, top, right, bottom, paint)
paint.setColor(Color.parseColor("#567898"))
canvas.drawText("HenCoder", 100, 100, paint)
1.1.1.2 setARGB(int a, int r, int g, int b)
參數(shù)用的是更直接的三原色與透明度的值
paint.setARGB(a, r, g, b)
canvas.drawRect(left, top, right, bottom, paint)
paint.setARGB(a, r, g, b)
canvas.drawLine(left, top, right, bottom, paint)
1.1.2 setShader(Shader shader) 設置 Shader
Shader 著色器壶栋,也是用于設置繪制顏色的辰如。著色器設置的是一個顏色方案,或者說是一套著色規(guī)則委刘。當設置了 Shader 之后丧没,Paint 在繪制圖形和文字時就不使用 setColor/ARGB() 設置的顏色了,而是使用 Shader 的方案中的顏色锡移。
在 Android 的繪制里使用 Shader 呕童,并不直接用 Shader 這個類,而是用它的幾個子類淆珊。具體來講有 LinearGradient RadialGradient SweepGradient BitmapShader ComposeShader :
1.1.2.1 LinearGradient 線性漸變
val shader = LinearGradient(x0, y0, x1, y1, Color.parseColor("#E91E63"),Color.parseColor("#123456"), Shader.TileMode.CLAMP)
paint.setShader(shader)
canvas.drawCircle(cx, cy, radius, paint)
置兩個點和兩種顏色夺饲,以這兩個點作為端點,使用兩種顏色的漸變來繪制顏色施符。
構造方法:
- LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile) 往声。
參數(shù):
- x0 y0 x1 y1:漸變的兩個端點的位置
- color0 color1 是端點的顏色tile:端點范圍之外的著色規(guī)則,類型是 TileMode戳吝。
TileMode 一共有 3 個值可選: CLAMP, MIRROR 和 REPEAT浩销。
- CLAMP 會在端點之外延續(xù)端點處的顏色;
- MIRROR 是鏡像模式听哭;
- REPEAT 是重復模式慢洋。
1.1.2.2 RadialGradient 輻射漸變
輻射漸變就是從中心向周圍輻射狀的漸變。
val shader = RadialGradient(cx, cy, radius, Color.parseColor("#111111"), Color.parseColor("#2222222"), Shader.TileMode.CLAMP)
paint.setShader(shader)
canvas.drawCircle(cx, cy, radius, paint)
構造方法:
- RadialGradient(float centerX, float centerY, float radius, int centerColor, int edgeColor, TileMode tileMode)陆盘。
參數(shù):
- centerX centerY:輻射中心的坐標
- radius:輻射半徑
- centerColor:輻射中心的顏色
- edgeColor:輻射邊緣的顏色
- tileMode:輻射范圍之外的著色模式普筹。
1.1.2.3 SweepGradient 掃描漸變
val shader = SweepGradient(cx, cy, Color.parseColor("#33333"),Color.parseColor("#444444"))
paint.setShader(shader)
canvas.drawCircle(cx, cy, radius, paint)
構造方法:
- SweepGradient(float cx, float cy, int color0, int color1)
參數(shù):
- cx cy :掃描的中心
- color0:掃描的起始顏色
- color1:掃描的終止顏色
1.1.2.4 BitmapShader
用 Bitmap 的像素來作為圖形或文字的填充
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.batman)
val shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
paint.setShader(shader)
canvas.drawCircle(cx, cy, radius, paint)
構造方法:
- BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)
參數(shù):
- bitmap:用來做模板的 Bitmap 對象
- tileX:橫向的 TileMode
- tileY:縱向的 TileMode蜡感。
1.1.2.5 ComposeShader 混合著色器
所謂混合牧愁,就是把兩個 Shader 一起使用。
// 第一個 Shader:頭像的 Bitmap
val bitmap1 = BitmapFactory.decodeResource(resources, R.drawable.batman)
val shader1 = BitmapShader(bitmap1, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
// 第二個 Shader:從上到下的線性漸變(由透明到黑色)
val bitmap2 = BitmapFactory.decodeResource(resources, R.drawable.batman_logo)
val shader2 = BitmapShader(bitmap2, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
// ComposeShader:結合兩個 Shader
val shader = ComposeShader(shader1, shader2, PorterDuff.Mode.SRC_OVER)
paint.setShader(shader)
canvas.drawCircle(cx, cy, radius, paint)
上面這段代碼中兩個 BitmapShader 來作為 ComposeShader() 的參數(shù)魔策,而 ComposeShader() 在硬件加速下是不支持兩個相同類型的 Shader 的酸员,所以這里也需要關閉硬件加速才能看到效果蜒车。
構造方法:
- ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)
參數(shù):
- shaderA, shaderB:兩個相繼使用的
- Shadermode: 兩個 Shader 的疊加模式讳嘱,即 shaderA 和 shaderB 應該怎樣共同繪制。它的類型是 PorterDuff.Mode 醇王。
PorterDuff.Mode
PorterDuff.Mode 一共有 17 個呢燥,可以分為兩類:
- Alpha 合成 (Alpha Compositing)
- 混合 (Blending)
第一類,Alpha 合成寓娩,其實就是 「PorterDuff」 這個詞所指代的算法叛氨。 「PorterDuff」 并不是一個具有實際意義的詞組,而是兩個人的名字(準確講是姓)棘伴。這兩個人當年共同發(fā)表了一篇論文寞埠,描述了 12 種將兩個圖像共同繪制的操作(即算法)。而這篇論文所論述的操作焊夸,都是關于 Alpha 通道(也就是我們通俗理解的「透明度」)的計算的仁连,后來人們就把這類計算稱為Alpha 合成 ( Alpha Compositing ) 。
看下效果吧阱穗。效果直接盜 Google 的官方文檔吧饭冬。
源圖像和目標圖像:
![RIE{0$QUU]EJ~]3F5OE8CE.png
Alpha 合成:
![WBOFB_3R)MM~M78{LQLDFO.png
第二類,混合揪阶,也就是 Photoshop 等制圖軟件里都有的那些混合模式(multiply
darken
lighten
之類的)昌抠。這一類操作的是顏色本身而不是 Alpha
通道,并不屬于 Alpha
合成鲁僚,所以和 Porter 與 Duff 這兩個人也沒什么關系炊苫,不過為了使用的方便,它們同樣也被 Google 加進了 PorterDuff.Mode
里冰沙。
官方文檔![C35C}H87(IA@E~L8M@ZCH8.png侨艾。
結論
從效果圖可以看出,Alpha 合成類的效果都比較直觀拓挥,基本上可以使用簡單的口頭表達來描述它們的算法(起碼對于不透明的源圖像和目標圖像來說是可以的)唠梨,例如 SRC_OVER 表示「二者都繪制,但要源圖像放在目標圖像的上面」侥啤,DST_IN 表示「只繪制目標圖像当叭,并且只繪制它和源圖像重合的區(qū)域」。
而混合類的效果就相對抽象一些愿棋,只從效果圖不太能看得出它們的著色算法科展,更看不出來它們有什么用均牢。
所以對于這些 Mode糠雨,正確的做法是:對于 Alpha 合成類的操作,掌握他們徘跪,并在實際開發(fā)中靈活運用甘邀。
好了琅攘,這些就是幾個 Shader 的具體介紹。
setShadowLayer(float radius, float dx, float dy, int shadowColor)
在之后的繪制內(nèi)容下面加一層陰影松邪。
paint.setShadowLayer(10, 0, 0, Color.RED)
canvas.drawText(text, 80, 300, paint);
方法的參數(shù)里坞琴, radius 是陰影的模糊范圍; dx dy 是陰影的偏移量逗抑; shadowColor 是陰影的顏色剧辐。
如果要清除陰影層,使用 clearShadowLayer() 邮府。
注意:
在硬件加速開啟的情況下荧关, setShadowLayer() 只支持文字的繪制,文字之外的繪制必須關閉硬件加速才能正常繪制陰影褂傀。
如果 shadowColor 是半透明的忍啤,陰影的透明度就使用 shadowColor 自己的透明度;而如果 shadowColor 是不透明的仙辟,陰影的透明度就使用 paint 的透明度同波。
setMaskFilter(MaskFilter maskfilter)
為之后的繪制設置 MaskFilter。上一個方法 setShadowLayer() 是設置的在繪制層下方的附加效果叠国;而這個 MaskFilter 和它相反未檩,設置的是在繪制層上方的附加效果。
到現(xiàn)在已經(jīng)有兩個 setXxxFilter(filter) 了煎饼。前面有一個 setColorFilter(filter) 讹挎,是對每個像素的顏色進行過濾;而這里的 setMaskFilter(filter) 則是基于整個畫面來進行過濾吆玖。
MaskFilter 有兩種:
- BlurMaskFilter
- EmbossMaskFilter筒溃。
BlurMaskFilter
模糊效果的 MaskFilter。
paint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.NORMAL))
canvas.drawBitmap(bitmap, 100, 100, paint)
它的構造方法 BlurMaskFilter(float radius, BlurMaskFilter.Blur style) 中沾乘, radius 參數(shù)是模糊的范圍怜奖, style 是模糊的類型。一共有四種:
- NORMAL: 內(nèi)外都模糊繪制
- SOLID: 內(nèi)部正常繪制翅阵,外部模糊
- INNER: 內(nèi)部模糊歪玲,外部不繪制
- OUTER: 內(nèi)部不繪制,外部模糊(什么鬼掷匠?)
EmbossMaskFilter
雕效果的 MaskFilter滥崩。
paint.setMaskFilter( EmbossMaskFilter(new float[]{0, 1, 1}, 0.2f, 8, 10))
canvas.drawBitmap(bitmap, 100, 100, paint)
它的構造方法 EmbossMaskFilter(float[] direction, float ambient, float specular, float blurRadius) 的參數(shù)里, direction 是一個 3 個元素的數(shù)組讹语,指定了光源的方向钙皮; ambient 是環(huán)境光的強度,數(shù)值范圍是 0 到 1; specular 是炫光的系數(shù)短条; blurRadius 是應用光線的范圍导匣。