Paint 詳解
Paint 的 API 大致可以分為 4 類:
- 顏色
- 效果
- drawText() 相關(guān)
- 初始化
1 顏色
Canvas 繪制的內(nèi)容,有三層對(duì)顏色的處理:

1.1 基本顏色
- 像素的基本顏色,根據(jù)繪制內(nèi)容的不同而有不同的控制方式: Canvas 的顏色填充類方法 drawColor/RGB/ARGB() 的顏色,是直接寫(xiě)在方法的參數(shù)里,通過(guò)參數(shù)來(lái)設(shè)置的;
- drawBitmap() 的顏色,是直接由 Bitmap 對(duì)象來(lái)提供的;
- 圖形和文字的繪制,它們的顏色就需要使用 paint 參數(shù)來(lái)額外設(shè)置(drawCircle() / drawPath() / drawText() ...)。
Paint 設(shè)置顏色的方法有兩種:
- 一種是直接用 Paint.setColor/ARGB() 來(lái)設(shè)置顏色;
- 另一種是使用 Shader 來(lái)指定著色方案。
1.1.1 直接設(shè)置顏色
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) 設(shè)置 Shader
Shader 著色器,也是用于設(shè)置繪制顏色的。著色器設(shè)置的是一個(gè)顏色方案,或者說(shuō)是一套著色規(guī)則。當(dāng)設(shè)置了 Shader 之后,Paint 在繪制圖形和文字時(shí)就不使用 setColor/ARGB() 設(shè)置的顏色了,而是使用 Shader 的方案中的顏色。
在 Android 的繪制里使用 Shader ,并不直接用 Shader 這個(gè)類,而是用它的幾個(gè)子類。具體來(lái)講有 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)
置兩個(gè)點(diǎn)和兩種顏色,以這兩個(gè)點(diǎn)作為端點(diǎn),使用兩種顏色的漸變來(lái)繪制顏色。
構(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)的顏色tile:端點(diǎn)范圍之外的著色規(guī)則,類型是 TileMode。
TileMode 一共有 3 個(gè)值可選: CLAMP, MIRROR 和 REPEAT。
- CLAMP 會(huì)在端點(diǎn)之外延續(xù)端點(diǎn)處的顏色;
- MIRROR 是鏡像模式;
- REPEAT 是重復(fù)模式。
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)
構(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 掃描漸變
val shader = SweepGradient(cx, cy, Color.parseColor("#33333"),Color.parseColor("#444444"))
paint.setShader(shader)
canvas.drawCircle(cx, cy, radius, paint)
構(gòu)造方法:
- SweepGradient(float cx, float cy, int color0, int color1)
參數(shù):
- cx cy :掃描的中心
- color0:掃描的起始顏色
- color1:掃描的終止顏色
1.1.2.4 BitmapShader
用 Bitmap 的像素來(lái)作為圖形或文字的填充
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)
構(gòu)造方法:
- BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)
參數(shù):
- bitmap:用來(lái)做模板的 Bitmap 對(duì)象
- tileX:橫向的 TileMode
- tileY:縱向的 TileMode。
1.1.2.5 ComposeShader 混合著色器
所謂混合,就是把兩個(gè) Shader 一起使用。
// 第一個(gè) Shader:頭像的 Bitmap
val bitmap1 = BitmapFactory.decodeResource(resources, R.drawable.batman)
val shader1 = BitmapShader(bitmap1, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
// 第二個(gè) Shader:從上到下的線性漸變(由透明到黑色)
val bitmap2 = BitmapFactory.decodeResource(resources, R.drawable.batman_logo)
val shader2 = BitmapShader(bitmap2, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
// ComposeShader:結(jié)合兩個(gè) Shader
val shader = ComposeShader(shader1, shader2, PorterDuff.Mode.SRC_OVER)
paint.setShader(shader)
canvas.drawCircle(cx, cy, radius, paint)
上面這段代碼中兩個(gè) BitmapShader 來(lái)作為 ComposeShader() 的參數(shù),而 ComposeShader() 在硬件加速下是不支持兩個(gè)相同類型的 Shader 的,所以這里也需要關(guān)閉硬件加速才能看到效果。
構(gòu)造方法:
- ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)
參數(shù):
- shaderA, shaderB:兩個(gè)相繼使用的
- Shadermode: 兩個(gè) Shader 的疊加模式,即 shaderA 和 shaderB 應(yīng)該怎樣共同繪制。它的類型是 PorterDuff.Mode 。
PorterDuff.Mode
PorterDuff.Mode 一共有 17 個(gè),可以分為兩類:
- Alpha 合成 (Alpha Compositing)
- 混合 (Blending)
第一類,Alpha 合成,其實(shí)就是 「PorterDuff」 這個(gè)詞所指代的算法。 「PorterDuff」 并不是一個(gè)具有實(shí)際意義的詞組,而是兩個(gè)人的名字(準(zhǔn)確講是姓)。這兩個(gè)人當(dāng)年共同發(fā)表了一篇論文,描述了 12 種將兩個(gè)圖像共同繪制的操作(即算法)。而這篇論文所論述的操作,都是關(guān)于 Alpha 通道(也就是我們通俗理解的「透明度」)的計(jì)算的,后來(lái)人們就把這類計(jì)算稱為Alpha 合成 ( Alpha Compositing ) 。
看下效果吧。效果直接盜 Google 的官方文檔吧。
源圖像和目標(biāo)圖像:
![RIE{0$QUU]EJ~]3F5OE8CE.png
Alpha 合成:

第二類,混合,也就是 Photoshop 等制圖軟件里都有的那些混合模式(multiply darken lighten 之類的)。這一類操作的是顏色本身而不是 Alpha 通道,并不屬于 Alpha 合成,所以和 Porter 與 Duff 這兩個(gè)人也沒(méi)什么關(guān)系,不過(guò)為了使用的方便,它們同樣也被 Google 加進(jìn)了 PorterDuff.Mode 里。
官方文檔![C35C}H87(IA@E~L8M@ZCH8.png。
結(jié)論
從效果圖可以看出,Alpha 合成類的效果都比較直觀,基本上可以使用簡(jiǎn)單的口頭表達(dá)來(lái)描述它們的算法(起碼對(duì)于不透明的源圖像和目標(biāo)圖像來(lái)說(shuō)是可以的),例如 SRC_OVER 表示「二者都繪制,但要源圖像放在目標(biāo)圖像的上面」,DST_IN 表示「只繪制目標(biāo)圖像,并且只繪制它和源圖像重合的區(qū)域」。
而混合類的效果就相對(duì)抽象一些,只從效果圖不太能看得出它們的著色算法,更看不出來(lái)它們有什么用。
所以對(duì)于這些 Mode,正確的做法是:對(duì)于 Alpha 合成類的操作,掌握他們,并在實(shí)際開(kāi)發(fā)中靈活運(yùn)用。
好了,這些就是幾個(gè) 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() 。
注意:
在硬件加速開(kāi)啟的情況下, setShadowLayer() 只支持文字的繪制,文字之外的繪制必須關(guān)閉硬件加速才能正常繪制陰影。
如果 shadowColor 是半透明的,陰影的透明度就使用 shadowColor 自己的透明度;而如果 shadowColor 是不透明的,陰影的透明度就使用 paint 的透明度。
setMaskFilter(MaskFilter maskfilter)
為之后的繪制設(shè)置 MaskFilter。上一個(gè)方法 setShadowLayer() 是設(shè)置的在繪制層下方的附加效果;而這個(gè) MaskFilter 和它相反,設(shè)置的是在繪制層上方的附加效果。
到現(xiàn)在已經(jīng)有兩個(gè) setXxxFilter(filter) 了。前面有一個(gè) setColorFilter(filter) ,是對(duì)每個(gè)像素的顏色進(jìn)行過(guò)濾;而這里的 setMaskFilter(filter) 則是基于整個(gè)畫(huà)面來(lái)進(jìn)行過(guò)濾。
MaskFilter 有兩種:
- BlurMaskFilter
- EmbossMaskFilter。
BlurMaskFilter
模糊效果的 MaskFilter。
paint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.NORMAL))
canvas.drawBitmap(bitmap, 100, 100, paint)
它的構(gòu)造方法 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)
它的構(gòu)造方法 EmbossMaskFilter(float[] direction, float ambient, float specular, float blurRadius) 的參數(shù)里, direction 是一個(gè) 3 個(gè)元素的數(shù)組,指定了光源的方向; ambient 是環(huán)境光的強(qiáng)度,數(shù)值范圍是 0 到 1; specular 是炫光的系數(shù); blurRadius 是應(yīng)用光線的范圍。