此文章為HenCoder的備份霞揉,感謝HenCoder這篇文章的作者
Paint
的Api大致分為4類
- 顏色
- 效果
-
drawText()
相關(guān) - 初始化
下面我就對這四類分別進(jìn)行介紹
1质礼、顏色
Canvas
繪制的內(nèi)容拣宏,有三層對顏色的處理
這圖大概看看就行,不用鉆研明白再往下看犬耻,因為等這章講完你就懂了。
1.1 基本顏色
像素的基本顏色执泰,很久繪制內(nèi)容的不同而有不同的控制方式:
-
Canvas
的顏色填充類方法drawColor/RGB/ARGB()
的顏色枕磁,是直接寫在方法的參數(shù)里,通過參數(shù)類設(shè)置的术吝; -
drawBitmap()
的顏色计济,是直接由Bitmap
對象提供的; - 圖形和文字的繪制排苍,它們的顏色就需要使用
paint
參數(shù)來額外設(shè)置了沦寂。
paint
設(shè)置顏色的方法有兩種:一種是直接用Paint.setColor/ARGB()
來設(shè)置顏色,另一種是使用Shader
來指定著色方案淘衙。
1.1.1 直接設(shè)置顏色
1.1.1.1 setColor(int color)
方法名和使用方法都非常簡單直接传藏,不在多說
paint.setColor(Color.parseColor("#009688"));//抄者注:也可寫成paint.setColor(0xff009688);0xff+#號后的顏色
canvas.drawRect(30,30,230,180,paint);
paint.setColor(Color.parseColor("#FF9800"));
canvas.drawLine(300, 30, 450, 180, paint);
paint.setColor(Color.parseColor("#E91E63"));
canvas.drawText("HenCoder", 500, 130, paint);
setColor() 對應(yīng)的get方法是getColor()
1.1.1.2 setARGB(int a,int r, int g,int b)
其實和setColor(color)
都是一樣一樣的,只是它的參數(shù)用的是更直接的三原色與透明度的值。實際運用中毯侦,setColor
和setARGB
哪個方便和順手用哪個吧
paint.setARGB(100,255,0,0);
canvas.drawRect(0,0,200,200,paint);
paint.setARGB(100,0,0,0);
canvas.drawLine(0,0,200,200,paint);
1.1.2 setShader(Shader shader)設(shè)置Shader
除了直接設(shè)置顏色哭靖,Paint
還可以使用Shader
。
Shader這個英文單詞很多人沒有見過侈离,它的中文名叫 [著色器] 试幽,也是用于繪制顏色的。[著色器]不是Android獨有的卦碾,它是圖形領(lǐng)域的一個通用概念铺坞,它和直接設(shè)置顏色的區(qū)別是,著色器設(shè)置的是一個顏色方案洲胖,或者說是一套著色規(guī)則济榨。當(dāng)設(shè)置了Shader
之后,Paint
在繪制圖形和文字是就不適用setColor/ARGB
設(shè)置的顏色了宾濒,而是使用Shader
的方案中的顏色腿短。
在Android的繪制里使用Shader
,并不直接使用Shader
這個類绘梦,而是用它的幾個子類橘忱。具體來講有LinearGradient
,RadialGradient
,SweepGradient
,BitampGradient
,ComposeShader
這么幾個:
1.1.2.1 LinearGradient 線性漸變
設(shè)置兩個點和兩種顏色,以這兩個點作為端點卸奉,使用每種顏色的漸變來繪制顏色钝诚。就像這樣:
Shader shader = new LinearGradient(100,100,500,500,Color.parseColor("#E91E63"),Color.parseColor("#2196F3"),Shader.TileMode.CLAMP);
paint.setShader(shader);
...
canvas.drawCircle(300,300,200,paint);
設(shè)置了
Shader
之后,繪制除了漸變顏色的元榄棵。(其他形狀及文字都可以這樣設(shè)置顏色凝颇,我只是沒給出圖)
注意:在設(shè)置了Shader
的情況下,setColor/ARGB
所設(shè)置的顏色就不在起作用疹鳄。
構(gòu)造方法:
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一共有3個值可選:CLAMP,MIRROR和REPEAT
-
CLAMP
:會在端點之外延續(xù)端點處的顏色; -
MIRROR
:鏡像模式, -
REPEAT
:重復(fù)模式瘪弓,具體的看一下例子就明白
CLAMP
:
MIRROR
:
REPEAT
:
1.1.2.2 RadialGradient 輻射漸變
輻射漸變很好理解垫蛆,就是從中心向周圍輻射狀的漸變。大概像這樣:
Shader shader = new RadialGradient(300, 300, 200, Color.parseColor("#E91E63"),Color.parseColor("#2196F3"), Shader.TileMode.CLAMP);
paint.setShader(shader);
...
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
:輻射范圍之外的著色模式袱饭。
CLAMP
:
MIRROR
:
REPEAT
:
SweepGradient 掃描漸變
又是一個漸變∏赫迹「掃描漸變」這個翻譯我也不知道精確不精確虑乖。大概是這樣:
Shader shader = new SweepGradient(300, 300, Color.parseColor("#E91E63"), Color.parseColor("#2196F3"));
paint.setShader(shader);
...
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
來著色(終于不是漸變了)。其實也就是用 Bitmap
的像素來作為圖形或文字的填充晾虑。大概像這樣:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.batman);
Shader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
...
canvas.drawCircle(300, 300, 200, paint);
嗯疹味,看著跟
Canvas.drawBitmap()
好像敖鼋小?事實上也是一樣的效果佛猛。如果你想繪制圓形的Bitmap
惑芭,就別用drawBitmap()
了,改用drawCircle()
+BitmapShader
就可以了(其他形狀同理)继找。
構(gòu)造方法:
BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)
參數(shù):
bitmap
:用來做模板的 Bitmap
對象
tileX
:橫向的 TileMode
tileY
:縱向的 TileMode
遂跟。
CLAMP
:
MIRROR
:
REPEAT
:
1.1.2.5 ComposeShader 混合著色器
所謂混合,就是把兩個 Shader 一起使用婴渡。
// 第一個 Shader:頭像的 Bitmap
Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.batman);
Shader shader1 = new BitmapShader(bitmap1, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
// 第二個 Shader:從上到下的線性漸變(由透明到黑色)
Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.batman_logo);
Shader shader2 = new BitmapShader(bitmap2, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
// ComposeShader:結(jié)合兩個 Shader
Shader shader = new ComposeShader(shader1, shader2, PorterDuff.Mode.SRC_OVER);
paint.setShader(shader);
...
canvas.drawCircle(300, 300, 300, paint);
注意:上面這段代碼中我使用了兩個
BitmapShader
來作為ComposeShader()
的參數(shù)幻锁,而ComposeShader()
在硬件加速下是不支持兩個相同類型的Shader
的,所以這里也需要關(guān)閉硬件加速才能看到效果边臼。
構(gòu)造方法:ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)
參數(shù):
shaderA
, shaderB
:兩個相繼使用的 Shader
mode
: 兩個 Shader
的疊加模式哄尔,即 shaderA
和 shaderB
應(yīng)該怎樣共同繪制。它的類型是 PorterDuff.Mode
柠并。
PorterDuff.Mode
PorterDuff.Mode
是用來指定兩個圖像共同繪制時的顏色策略的岭接。它是一個 enum,不同的Mode
可以指定不同的策略臼予∶鳎「顏色策略」的意思,就是說把源圖像繪制到目標(biāo)圖像處時應(yīng)該怎樣確定二者結(jié)合后的顏色粘拾,而對于ComposeShader(shaderA, shaderB, mode)
這個具體的方法窄锅,就是指應(yīng)該怎樣把shaderB
繪制在shaderA
上來得到一個結(jié)合后的Shader
。沒有聽說過
PorterDuff.Mode
的人缰雇,看到這里很可能依然會一頭霧水:「什么怎么結(jié)合入偷?就……兩個圖像一疊加,結(jié)合唄械哟?還能怎么結(jié)合疏之?」你還別說,還真的是有很多種策略來結(jié)合暇咆。最符合直覺的結(jié)合策略锋爪,就是我在上面這個例子中使用的
Mode
:SRC_OVER
。它的算法非常直觀:就像上面圖中的那樣糯崎,把源圖像直接鋪在目標(biāo)圖像上。不過河泳,除了這種沃呢,其實還有一些其他的結(jié)合方式。例如如果我把上面例子中的參數(shù)mode
改為PorterDuff.Mode.DST_OUT
拆挥,就會變成挖空效果:
而如果再把mode
改為PorterDuff.Mode.DST_IN
薄霜,就會變成蒙版摳圖效果:
這下明白了吧某抓?
具體來說, PorterDuff.Mode
一共有 17 個惰瓜,可以分為兩類:
- Alpha 合成 (Alpha Compositing)
- 混合 (Blending)
第一類否副,Alpha 合成,其實就是 「PorterDuff」 這個詞所指代的算法崎坊。 「PorterDuff」 并不是一個具有實際意義的詞組备禀,而是兩個人的名字(準(zhǔn)確講是姓)。這兩個人當(dāng)年共同發(fā)表了一篇論文奈揍,描述了 12 種將兩個圖像共同繪制的操作(即算法)曲尸。而這篇論文所論述的操作,都是關(guān)于 Alpha 通道(也就是我們通俗理解的「透明度」)的計算的男翰,后來人們就把這類計算稱為Alpha 合成 ( Alpha Compositing ) 另患。
看下效果吧。效果直接盜 Google 的官方文檔了蛾绎。
源圖像和目標(biāo)圖像:
Alpha 合成:
第二類昆箕,混合,也就是 Photoshop 等制圖軟件里都有的那些混合模式(multiply
darken
lighten
之類的)租冠。這一類操作的是顏色本身而不是 Alpha
通道鹏倘,并不屬于 Alpha
合成,所以和 Porter 與 Duff 這兩個人也沒什么關(guān)系肺稀,不過為了使用的方便第股,它們同樣也被 Google 加進(jìn)了 PorterDuff.Mode
里。
效果依然盜 官方文檔话原。
結(jié)論
從效果圖可以看出夕吻,Alpha 合成類的效果都比較直觀,基本上可以使用簡單的口頭表達(dá)來描述它們的算法(起碼對于不透明的源圖像和目標(biāo)圖像來說是可以的)繁仁,例如 SRC_OVER
表示「二者都繪制涉馅,但要源圖像放在目標(biāo)圖像的上面」,DST_IN
表示「只繪制目標(biāo)圖像黄虱,并且只繪制它和源圖像重合的區(qū)域」稚矿。
而混合類的效果就相對抽象一些,只從效果圖不太能看得出它們的著色算法捻浦,更看不出來它們有什么用晤揣。不過沒關(guān)系,你如果拿著這些名詞去問你司的設(shè)計師朱灿,他們八成都能給你說出來個 123昧识。
所以對于這些 Mode
,正確的做法是:對于 Alpha 合成類的操作盗扒,掌握他們跪楞,并在實際開發(fā)中靈活運用缀去;而對于混合類的,你只要把它們的名字記住就好了甸祭,這樣當(dāng)某一天設(shè)計師告訴你「我要做這種混合效果」的時候缕碎,你可以馬上知道自己能不能做,怎么做池户。
另外:PorterDuff.Mode
建議你動手用一下試試咏雌,對加深理解有幫助。
好了煞檩,這些就是幾個 Shader 的具體介紹处嫌。
除了使用 setColor/ARGB() 和 setShader() 來設(shè)置基本顏色, Paint 還可以來設(shè)置 ColorFilter斟湃,來對顏色進(jìn)行第二層處理熏迹。
1.2 setColorFilter(ColorFilter colorFilter)
ColorFilter 這個類,它的名字已經(jīng)足夠解釋它的作用:為繪制設(shè)置顏色過濾凝赛。顏色過濾的意思注暗,就是為繪制的內(nèi)容設(shè)置一個統(tǒng)一的過濾策略,然后 Canvas.drawXXX() 方法會對每個像素都進(jìn)行過濾后再繪制出來墓猎。舉幾個現(xiàn)實中比較常見的顏色過濾的例子:
-
有色光照射:
-
有色玻璃透視:
-
膠卷:
在 Paint 里設(shè)置 ColorFilter 捆昏,使用的是 Paint.setColorFilter(ColorFilter filter) 方法。 ColorFilter 并不直接使用毙沾,而是使用它的子類骗卜。它共有三個子類:LightingColorFilter PorterDuffColorFilter 和 ColorMatrixColorFilter。
1.2.1 LightingColorFilter
這個 LightingColorFilter 是用來模擬簡單的光照效果的左胞。
LightingColorFilter 的構(gòu)造方法是 LightingColorFilter(int mul, int add) 寇仓,參數(shù)里的 mul 和 add 都是和顏色值格式相同的 int 值,其中 mul
用來和目標(biāo)像素相乘(抄著注烤宙,根據(jù)下面看這里應(yīng)該是除)遍烦,add
用來和目標(biāo)像素相加:
R' = R * mul.R / 0xff + add.R
G' = G * mul.G / 0xff + add.G
B' = B * mul.B / 0xff + add.B
一個「保持原樣」的「基本 LightingColorFilter 」,mul 為 0xffffff躺枕,add 為 0x000000(也就是0)服猪,那么對于一個像素,它的計算過程就是:
R' = R * 0xff / 0xff + 0x0 = R // R' = R
G' = G * 0xff / 0xff + 0x0 = G // G' = G
B' = B * 0xff / 0xff + 0x0 = B // B' = B
基于這個「基本 LightingColorFilter 」拐云,你就可以修改一下做出其他的 filter罢猪。比如,如果你想去掉原像素中的紅色叉瘩,可以把它的 mul 改為 0x00ffff (紅色部分為 0 ) 膳帕,那么它的計算過程就是:
R' = R * 0x0 / 0xff + 0x0 = 0 // 紅色被移除
G' = G * 0xff / 0xff + 0x0 = G
B' = B * 0xff / 0xff + 0x0 = B
具體效果是這樣的:
ColorFilter lightingColorFilter = new LightingColorFilter(0x00ffff, 0x000000);
paint.setColorFilter(lightingColorFilter);
表情忽然變得陰郁了
或者,如果你想讓它的綠色更亮一些房揭,就可以把它的 add 改為 0x003000 (綠色部分為 0x30 )备闲,那么它的計算過程就是:
R' = R * 0xff / 0xff + 0x0 = R
G' = G * 0xff / 0xff + 0x30 = G + 0x30 // 綠色被加強
B' = B * 0xff / 0xff + 0x0 = B
效果是這樣:
ColorFilter lightingColorFilter = new LightingColorFilter(0xffffff, 0x003000);
paint.setColorFilter(lightingColorFilter);
這樣的表情才陽光
至于怎么修改參數(shù)來模擬你想要的某種具體光照效果,你就別問我了捅暴,還是跟你司設(shè)計師討論吧恬砂,這個我不專業(yè)……
1.2.2 PorterDuffColorFilter
這個 PorterDuffColorFilter 的作用是使用一個指定的顏色和一種指定的 PorterDuff.Mode 來與繪制對象進(jìn)行合成。它的構(gòu)造方法是 PorterDuffColorFilter(int color, PorterDuff.Mode mode) 其中的 color 參數(shù)是指定的顏色蓬痒, mode 參數(shù)是指定的 Mode泻骤。同樣也是 PorterDuff.Mode ,不過和 ComposeShader 不同的是梧奢,PorterDuffColorFilter 作為一個 ColorFilter狱掂,只能指定一種顏色作為源,而不是一個 Bitmap亲轨。
PorterDuff.Mode 前面已經(jīng)講過了趋惨,而 PorterDuffColorFilter 本身的使用是非常簡單的,所以不再展開講惦蚊。
1.2.3 ColorMatrixColorFilter
這個就厲害了器虾。ColorMatrixColorFilter 使用一個 ColorMatrix 來對顏色進(jìn)行處理。 ColorMatrix 這個類蹦锋,內(nèi)部是一個 4x5 的矩陣:
[ a, b, c, d, e,
f, g, h, i, j,
k, l, m, n, o,
p, q, r, s, t ]
通過計算兆沙, ColorMatrix 可以把要繪制的像素進(jìn)行轉(zhuǎn)換。對于顏色 [R, G, B, A] 莉掂,轉(zhuǎn)換算法是這樣的:
R’ = a*R + b*G + c*B + d*A + e;
G’ = f*R + g*G + h*B + i*A + j;
B’ = k*R + l*G + m*B + n*A + o;
A’ = p*R + q*G + r*B + s*A + t;
ColorMatrix
有一些自帶的方法可以做簡單的轉(zhuǎn)換葛圃,例如可以使用 setSaturation(float sat)
來設(shè)置飽和度;另外你也可以自己去設(shè)置它的每一個元素來對轉(zhuǎn)換效果做精細(xì)調(diào)整憎妙。具體怎樣設(shè)置會有怎樣的效果库正,我就不講了(其實是我也不太會??)。如果你有需求尚氛,可以試一下程大治同學(xué)做的這個庫:StyleImageView
以上诀诊,就是 Paint
對顏色的第二層處理:通過 setColorFilter(colorFilter)
來加工顏色。
除了基本顏色的設(shè)置( setColor/ARGB()
, setShader()
)以及基于原始顏色的過濾( setColorFilter()
)之外阅嘶,Paint
最后一層處理顏色的方法是 setXfermode(Xfermode xfermode)
属瓣,它處理的是「當(dāng)顏色遇上 View」的問題。
1.3 setXfermode(Xfermode xfermode)
"Xfermode" 其實就是 "Transfer mode"讯柔,用 "X" 來代替 "Trans" 是一些美國人喜歡用的簡寫方式抡蛙。嚴(yán)謹(jǐn)?shù)刂v, Xfermode 指的是你要繪制的內(nèi)容和 Canvas 的目標(biāo)位置的內(nèi)容應(yīng)該怎樣結(jié)合計算出最終的顏色魂迄。但通俗地說粗截,其實就是要你以繪制的內(nèi)容作為源圖像,以 View 中已有的內(nèi)容作為目標(biāo)圖像,選取一個 PorterDuff.Mode 作為繪制內(nèi)容的顏色處理方案台妆。就像這樣:
ColorFilter lightingColorFilter = new LightingColorFilter(0x00ffff, 0x000000);
paint.setColorFilter(lightingColorFilter);
又是 PorterDuff.Mode
。 PorterDuff.Mode
在 Paint
一共有三處 API 胳徽,它們的工作原理都一樣婿屹,只是用途不同:
另外灭美,從上面的示例代碼可以看出,創(chuàng)建 Xfermode
的時候其實是創(chuàng)建的它的子類 PorterDuffXfermode
昂利。而事實上届腐,Xfermode
也只有這一個子類。所以在設(shè)置 Xfermode
的時候不用多想蜂奸,直接用 PorterDuffXfermode
吧犁苏。
「只有一個子類?扩所?围详?什么設(shè)計?」
其實在更早的 Android 版本中祖屏,Xfermode
還有別的子類短曾,但別的子類現(xiàn)在已經(jīng)deprecated
了,如今只剩下了PorterDuffXfermode
赐劣。所以目前它的使用看起來好像有點啰嗦嫉拐,但其實是由于歷史遺留問題。
Xfermode 注意事項
Xfermode 使用很簡單魁兼,不過有兩點需要注意:
1. 使用離屏緩沖(Off-screen Buffer)
實質(zhì)上婉徘,上面這段例子代碼,如果直接執(zhí)行的話是不會繪制出圖中效果的咐汞,程序的繪制也不會像上面的動畫那樣執(zhí)行盖呼,而是會像這樣:
為什么會這樣?
按照邏輯我們會認(rèn)為化撕,在第二步畫圓的時候几晤,跟它共同計算的是第一步繪制的方形。但實際上植阴,卻是整個 View
的顯示區(qū)域都在畫圓的時候參與計算蟹瘾,并且 View
自身的底色并不是默認(rèn)的透明色,而且是遵循一種迷之邏輯掠手,導(dǎo)致不僅繪制的是整個圓的范圍憾朴,而且在范圍之外都變成了黑色。就像這樣:
這……那可如何是好喷鸽?
要想使用 setXfermode()
正常繪制众雷,必須使用離屏緩存 (Off-screen Buffer) 把內(nèi)容繪制在額外的層上,再把繪制好的內(nèi)容貼回 View 中。也就是這樣:
通過使用離屏緩沖砾省,把要繪制的內(nèi)容單獨繪制在緩沖層鸡岗, Xfermode
的使用就不會出現(xiàn)奇怪的結(jié)果了。使用離屏緩沖有兩種方式:
-
Canvas.saveLayer()
saveLayer()
可以做短時的離屏緩沖编兄。使用方法很簡單纤房,在繪制代碼的前后各加一行代碼,在繪制之前保存翻诉,繪制之后恢復(fù):int saved = canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG); canvas.drawBitmap(rectBitmap, 0, 0, paint); // 畫方 paint.setXfermode(xfermode); // 設(shè)置 Xfermode canvas.drawBitmap(circleBitmap, 0, 0, paint); // 畫圓 paint.setXfermode(null); // 用完及時清除 Xfermode canvas.restoreToCount(saved);
-
View.setLayerType()
View.setLayerType()
是直接把整個View
都繪制在離屏緩沖中。setLayerType(LAYER_TYPE_HARDWARE)
是使用 GPU 來緩沖捌刮,setLayerType(LAYER_TYPE_SOFTWARE)
是直接直接用一個Bitmap
來緩沖碰煌。
如果沒有特殊需求,可以選用第一種方法 Canvas.saveLayer()
來設(shè)置離屏緩沖绅作,以此來獲得更高的性能芦圾。更多關(guān)于離屏緩沖的信息,可以看官方文檔中對于硬件加速的介紹俄认。
2. 控制好透明區(qū)域
使用 Xfermode 來繪制的內(nèi)容个少,除了注意使用離屏緩沖,還應(yīng)該注意控制它的透明區(qū)域不要太小眯杏,要讓它足夠覆蓋到要和它結(jié)合繪制的內(nèi)容夜焦,否則得到的結(jié)果很可能不是你想要的。我用圖片來具體說明一下:
如圖所示岂贩,由于透明區(qū)域過小而覆蓋不到的地方茫经,將不會受到 Xfermode 的影響。
好萎津,到此為止卸伞,前面講的就是 Paint
的第一類 API——關(guān)于顏色的三層設(shè)置:直接設(shè)置顏色的 API 用來給圖形和文字設(shè)置顏色; setColorFilter()
用來基于顏色進(jìn)行過濾處理锉屈; setXfermode()
用來處理源圖像和 View
已有內(nèi)容的關(guān)系荤傲。
再貼一次本章開始處的圖作為回顧:
2 效果
效果類的 API ,指的就是抗鋸齒颈渊、填充/輪廓遂黍、線條寬度等等這些。
2.1 setAntiAlias (boolean aa) 設(shè)置抗鋸齒
抗鋸齒在上一節(jié)已經(jīng)講過了俊嗽,話不多說妓湘,直接上圖:
抗鋸齒默認(rèn)是關(guān)閉的,如果需要抗鋸齒乌询,需要顯式地打開榜贴。另外,除了 setAntiAlias(aa)
方法,打開抗鋸齒還有一個更方便的方式:構(gòu)造方法唬党。創(chuàng)建 Paint
對象的時候鹃共,構(gòu)造方法的參數(shù)里加一個 ANTI_ALIAS_FLAG
的 flag,就可以在初始化的時候就開啟抗鋸齒驶拱。
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
2.2 setStyle(Paint.Style style)
setStyle(style)
也在上一節(jié)講過了霜浴,用來設(shè)置圖形是線條風(fēng)格還是填充風(fēng)格的(也可以二者并用):
paint.setStyle(Paint.Style.FILL); // FILL 模式,填充
canvas.drawCircle(300, 300, 200, paint);
paint.setStyle(Paint.Style.STROKE); // STROKE 模式蓝纲,畫線
canvas.drawCircle(300, 300, 200, paint);
paint.setStyle(Paint.Style.FILL_AND_STROKE); // FILL_AND_STROKE 模式阴孟,填充 + 畫線
canvas.drawCircle(300, 300, 200, paint);
FILL
模式是默認(rèn)模式,所以如果之前沒有設(shè)置過其他的 Style
税迷,可以不用 setStyle(Paint.Style.FILL)
這句永丝。
2.3 線條形狀
設(shè)置線條形狀的一共有 4 個方法:setStrokeWidth(float width)
, setStrokeCap(Paint.Cap cap)
, setStrokeJoin(Paint.Join join)
, setStrokeMiter(float miter)
。
2.3.1 setStrokeWidth(float width)
設(shè)置線條寬度箭养。單位為像素慕嚷,默認(rèn)值是 0。
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(1);
canvas.drawCircle(150, 125, 100, paint);
paint.setStrokeWidth(5);
canvas.drawCircle(400, 125, 100, paint);
paint.setStrokeWidth(40);
canvas.drawCircle(650, 125, 100, paint);
線條寬度 0 和 1 的區(qū)別
默認(rèn)情況下毕泌,線條寬度為 0喝检,但你會發(fā)現(xiàn),這個時候它依然能夠畫出線撼泛,線條的寬度為 1 像素挠说。那么它和線條寬度為 1 有什么區(qū)別呢?
其實這個和后面要講的一個「幾何變換」有關(guān):你可以為
Canvas
設(shè)置Matrix
來實現(xiàn)幾何變換(如放大愿题、縮小纺涤、平移、旋轉(zhuǎn))抠忘,在幾何變換之后Canvas
繪制的內(nèi)容就會發(fā)生相應(yīng)變化撩炊,包括線條也會加粗,例如 2 像素寬度的線條在Canvas
放大 2 倍后會被以 4 像素寬度來繪制崎脉。而當(dāng)線條寬度被設(shè)置為 0 時拧咳,它的寬度就被固定為 1 像素,就算Canvas
通過幾何變換被放大囚灼,它也依然會被以 1 像素寬度來繪制骆膝。Google 在文檔中把線條寬度為 0 時稱作「hairline mode(發(fā)際線模式)」。
2.3.2 setStrokeCap(Paint.Cap cap)
設(shè)置線頭的形狀灶体。線頭形狀有三種:BUTT
平頭阅签、ROUND
圓頭、SQUARE
方頭蝎抽。默認(rèn)為 BUTT
政钟。
放出「平頭」「圓頭」「方頭」這種翻譯我始終有點糾結(jié):既覺得自己翻譯得簡潔清晰盡顯機智,同時又擔(dān)心用詞會不會有點太過通俗,讓人覺得我不夠高貴冷艷养交?
當(dāng)線條的寬度是 1 像素時精算,這三種線頭的表現(xiàn)是完全一致的,全是 1 個像素的點碎连;而當(dāng)線條變粗的時候灰羽,它們就會表現(xiàn)出不同的樣子:
虛線是額外加的,虛線左邊是線的實際長度鱼辙,虛線右邊是線頭廉嚼。有了虛線作為輔助,可以清楚地看出 BUTT
和 SQUARE
的區(qū)別倒戏。
2.3.3 setStrokeJoin(Paint.Join join)
設(shè)置拐角的形狀怠噪。有三個值可以選擇:MITER
尖角、 BEVEL
平角和 ROUND
圓角峭梳。默認(rèn)為 MITER
。
輔助理解:
MITER 在現(xiàn)實中其實就是這玩意:
而 BEVEL 是這玩意:
2.3.4 setStrokeMiter(float miter)
這個方法是對于 setStrokeJoin()
的一個補充蹂喻,它用于設(shè)置 MITER
型拐角的延長線的最大值葱椭。所謂「延長線的最大值」,是這么一回事:
當(dāng)線條拐角為 MITER
時口四,拐角處的外緣需要使用延長線來補償:
而這種補償方案會有一個問題:如果拐角的角度太小孵运,就有可能由于出現(xiàn)連接點過長的情況。比如這樣:
所以為了避免意料之外的過長的尖角出現(xiàn)蔓彩, MITER
型連接點有一個額外的規(guī)則:當(dāng)尖角過長時治笨,自動改用 BEVEL
的方式來渲染連接點。例如上圖的這個尖角赤嚼,在默認(rèn)情況下是不會出現(xiàn)的旷赖,而是會由于延長線過長而被轉(zhuǎn)為 BEVEL
型連接點:
至于多尖的角屬于過于尖,尖到需要轉(zhuǎn)為使用 BEVEL
來繪制更卒,則是由一個屬性控制的等孵,而這個屬性就是 setStrokeMiter(miter)
方法中的 miter
參數(shù)。miter
參數(shù)是對于轉(zhuǎn)角長度的限制蹂空,具體來講俯萌,是指尖角的外緣端點和內(nèi)部拐角的距離與線條寬度的比。也就是下面這兩個長度的比:
用幾何知識很容易得出這個比值的計算公式:如果拐角的大小為 θ 上枕,那么這個比值就等于 1 / sin ( θ / 2 ) 咐熙。
這個 miter limit 的默認(rèn)值是 4,對應(yīng)的是一個大約 29° 的銳角:
默認(rèn)情況下辨萍,大于這個角的尖角會被保留棋恼,而小于這個夾角的就會被「削成平頭」
所以,這個方法雖然名叫
setStrokeMiter(miter)
,但它其實設(shè)置的是「 線條在Join
類型為MITER
時對于MITER
的長度限制」蘸泻。它的這個名字雖然短琉苇,但卻存在一定的迷惑性,如果叫setStrokeJoinMiterLimit(limit)
就更準(zhǔn)確了悦施。 Google 的工程師沒有這么給它命名并扇,大概也是不想傷害大家的手指吧,畢竟程序員何苦為難程序員抡诞。
以上就是 4 個關(guān)于線條形狀的方法: setStrokeWidth(width)
setStrokeCap(cap)
setStrokeJoint(join)
和 setStrokeMiter(miter)
穷蛹。
2.4 色彩優(yōu)化
Paint
的色彩優(yōu)化有兩個方法: setDither(boolean dither)
和 setFilterBitmap(boolean filter)
。它們的作用都是讓畫面顏色變得更加「順眼」昼汗,但原理和使用場景是不同的肴熏。
2.4.1 setDither(boolean dither)
設(shè)置圖像的抖動。
在介紹抖動之前顷窒,先來看一個猥瑣男:
注意毛利小五郎臉上的紅暈蛙吏,它們并不是使用一片淡紅色涂抹出來的,而是畫了三道深色的紅線鞋吉。這三道深色紅線放在臉上鸦做,給人的視覺效果就成了「淡淡的紅暈」。
抖動的原理和這個類似谓着。所謂抖動(注意泼诱,它就叫抖動,不是防抖動赊锚,也不是去抖動治筒,有些人在翻譯的時候自作主張地加了一個「防」字或者「去」字,這是不對的)舷蒲,是指把圖像從較高色彩深度(即可用的顏色數(shù))向較低色彩深度的區(qū)域繪制時耸袜,在圖像中有意地插入噪點,通過有規(guī)律地擾亂圖像來讓圖像對于肉眼更加真實的做法牲平。
比如向 1 位色彩深度的區(qū)域中繪制灰色句灌,由于 1 位深度只包含黑和白兩種顏色,在默認(rèn)情況下欠拾,即不加抖動的時候胰锌,只能選擇向上或向下選擇最接近灰色的白色或黑色來繪制,那么顯示出來也只能是一片白或者一片黑藐窄。而加了抖動后资昧,就可以繪制出讓肉眼識別為灰色的效果了:
瞧,像上面這樣荆忍,用黑白相間的方式來繪制格带,就可以騙過肉眼撤缴,讓肉眼辨別為灰色了。
嗯叽唱?你說你看不出灰色屈呕,只看出黑白相間?沒關(guān)系棺亭,那是因為像素顆粒太大虎眨,我把像素顆粒縮小镶摘,看到完整效果你就會發(fā)現(xiàn)變灰了:
這下變灰了吧嗽桩?
什么,還沒有變灰凄敢?那一定是你看圖的姿勢不對了碌冶。
不過,抖動可不只可以用在純色的繪制涝缝。在實際的應(yīng)用場景中扑庞,抖動更多的作用是在圖像降低色彩深度繪制時,避免出現(xiàn)大片的色帶與色塊拒逮。效果盜一下維基百科的圖:
看著很牛逼對吧罐氨?確實很牛逼,而且在 Android 里使用起來也很簡單消恍,一行代碼就搞定:
paint.setDither(true);
只要加這么一行代碼岂昭,之后的繪制就是加抖動的了以现。
不過對于現(xiàn)在(2017年)而言狠怨, setDither(dither)
已經(jīng)沒有當(dāng)年那么實用了,因為現(xiàn)在的 Android 版本的繪制邑遏,默認(rèn)的色彩深度已經(jīng)是 32 位的 ARGB_8888
佣赖,效果已經(jīng)足夠清晰了。只有當(dāng)你向自建的 Bitmap
中繪制记盒,并且選擇 16 位色的 ARGB_4444
或者 RGB_565
的時候憎蛤,開啟它才會有比較明顯的效果。
2.4.2 setFilterBitmap(boolean filter)
設(shè)置是否使用雙線性過濾來繪制 Bitmap
纪吮。
圖像在放大繪制的時候俩檬,默認(rèn)使用的是最近鄰插值過濾,這種算法簡單碾盟,但會出現(xiàn)馬賽克現(xiàn)象棚辽;而如果開啟了雙線性過濾,就可以讓結(jié)果圖像顯得更加平滑冰肴。效果依然盜維基百科的圖:
牛逼吧屈藐?而且它的使用同樣也很簡單:
paint.setFilterBitmap(true);
加上這一行榔组,在放大繪制 Bitmap
的時候就會使用雙線性過濾了。
以上就是 Paint
的兩個色彩優(yōu)化的方法: setDither(dither)
联逻,設(shè)置抖動來優(yōu)化色彩深度降低時的繪制效果搓扯; setFilterBitmap(filterBitmap)
,設(shè)置雙線性過濾來優(yōu)化 Bitmap
放大繪制的效果包归。
2.5 setPathEffect(PathEffect effect)
使用 PathEffect
來給圖形的輪廓設(shè)置效果锨推。對 Canvas
所有的圖形繪制有效,也就是 drawLine()``drawCircle()
drawPath()
這些方法箫踩。大概像這樣:
PathEffect pathEffect = new DashPathEffect(new float[]{10, 5}, 10);
paint.setPathEffect(pathEffect);
...
canvas.drawCircle(300, 300, 200, paint);
下面就具體說一下 Android 中的 6 種 PathEffect
爱态。PathEffect
分為兩類,單一效果的 CornerPathEffect``DiscretePathEffect
DashPathEffect
PathDashPathEffect
境钟,和組合效果的 SumPathEffect
ComposePathEffect
锦担。
2.5.1 CornerPathEffect
把所有拐角變成圓角。
PathEffect pathEffect = new CornerPathEffect(20);
paint.setPathEffect(pathEffect);
...
canvas.drawPath(path, paint);
它的構(gòu)造方法 CornerPathEffect(float radius)
的參數(shù) radius
是圓角的半徑慨削。
2.5.2 DiscretePathEffect
把線條進(jìn)行隨機的偏離洞渔,讓輪廓變得亂七八糟。亂七八糟的方式和程度由參數(shù)決定缚态。
PathEffect pathEffect = new DiscretePathEffect(20, 5);
paint.setPathEffect(pathEffect);
...
canvas.drawPath(path, paint);
DiscretePathEffect
具體的做法是磁椒,把繪制改為使用定長的線段來拼接,并且在拼接的時候?qū)β窂竭M(jìn)行隨機偏離玫芦。它的構(gòu)造方法 DiscretePathEffect(float segmentLength, float deviation)
的兩個參數(shù)中浆熔, segmentLength
是用來拼接的每個線段的長度, deviation
是偏離量桥帆。這兩個值設(shè)置得不一樣医增,顯示效果也會不一樣,具體的你自己多試幾次就明白了老虫,這里不再貼更多的圖叶骨。
2.5.3 DashPathEffect
使用虛線來繪制線條。
PathEffect pathEffect = new DashPathEffect(new float[]{20, 10, 5, 10}, 0);
paint.setPathEffect(pathEffect);
...
canvas.drawPath(path, paint);
它的構(gòu)造方法 DashPathEffect(float[] intervals, float phase)
中祈匙, 第一個參數(shù) intervals
是一個數(shù)組忽刽,它指定了虛線的格式:數(shù)組中元素必須為偶數(shù)(最少是 2 個),按照「畫線長度夺欲、空白長度跪帝、畫線長度、空白長度」……的順序排列些阅,例如上面代碼中的 20, 5, 10, 5
就表示虛線是按照「畫 20 像素伞剑、空 5 像素、畫 10 像素扑眉、空 5 像素」的模式來繪制纸泄;第二個參數(shù) phase
是虛線的偏移量赖钞。
2.5.4 PathDashPathEffect
這個方法比 DashPathEffect
多一個前綴 Path
,所以顧名思義聘裁,它是使用一個 Path
來繪制「虛線」雪营。具體看圖吧:
Path dashPath = ...; // 使用一個三角形來做 dash
PathEffect pathEffect = new PathDashPathEffect(dashPath, 40, 0,
PathDashPathEffectStyle.TRANSLATE);
paint.setPathEffect(pathEffect);
...
canvas.drawPath(path, paint);
它的構(gòu)造方法 PathDashPathEffect(Path shape, float advance, float phase, PathDashPathEffect.Style style)
中, shape
參數(shù)是用來繪制的 Path
衡便; advance
是兩個相鄰的 shape
段之間的間隔献起,不過注意,這個間隔是兩個 shape
段的起點的間隔镣陕,而不是前一個的終點和后一個的起點的距離谴餐; phase
和 DashPathEffect
中一樣,是虛線的偏移呆抑;最后一個參數(shù) style
岂嗓,是用來指定拐彎改變的時候 shape
的轉(zhuǎn)換方式。style
的類型為 PathDashPathEffect.Style
鹊碍,是一個 enum
厌殉,具體有三個值:
-
TRANSLATE
:位移 -
ROTATE
:旋轉(zhuǎn) -
MORPH
:變體
2.5.5 SumPathEffect
這是一個組合效果類的 PathEffect
。它的行為特別簡單侈咕,就是分別按照兩種 PathEffect
分別對目標(biāo)進(jìn)行繪制公罕。
PathEffect dashEffect = new DashPathEffect(new float[]{20, 10}, 0);
PathEffect discreteEffect = new DiscretePathEffect(20, 5);
pathEffect = new SumPathEffect(dashEffect, discreteEffect);
...
canvas.drawPath(path, paint);
2.5.6 ComposePathEffect
這也是一個組合效果類的 PathEffect
。不過它是先對目標(biāo) Path
使用一個 PathEffect
耀销,然后再對這個改變后的 Path
使用另一個 PathEffect
楼眷。
PathEffect dashEffect = new DashPathEffect(new float[]{20, 10}, 0);
PathEffect discreteEffect = new DiscretePathEffect(20, 5);
pathEffect = new ComposePathEffect(dashEffect, discreteEffect);
...
canvas.drawPath(path, paint);
它的構(gòu)造方法 ComposePathEffect(PathEffect outerpe, PathEffect innerpe)
中的兩個 PathEffect
參數(shù), innerpe
是先應(yīng)用的熊尉, outerpe
是后應(yīng)用的罐柳。所以上面的代碼就是「先偏離,再變虛線」帽揪。而如果把兩個參數(shù)調(diào)換硝清,就成了「先變虛線辅斟,再偏離」转晰。至于具體的視覺效果……我就不貼圖了,你自己試試看吧士飒!
上面這些就是 Paint
中的 6 種 PathEffect
查邢。它們有的是有獨立效果的,有的是用來組合不同的 PathEffect
的酵幕,功能各不一樣扰藕。
注意:
PathEffect
在有些情況下不支持硬件加速,需要關(guān)閉硬件加速才能正常使用:
Canvas.drawLine()
和Canvas.drawLines()
方法畫直線時芳撒,setPathEffect()
是不支持硬件加速的邓深;PathDashPathEffect
對硬件加速的支持也有問題未桥,所以當(dāng)使用PathDashPathEffect
的時候,最好也把硬件加速關(guān)了芥备。
剩下的兩個效果類方法:setShadowLayer()
和 setMaskFilter()
冬耿,它們和前面的效果類方法有點不一樣:它們設(shè)置的是「附加效果」,也就是基于在繪制內(nèi)容的額外效果萌壳。
2.6 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()
只支持文字的繪制勒庄,文字之外的繪制必須關(guān)閉硬件加速才能正常繪制陰影。如果
shadowColor
是半透明的瘫里,陰影的透明度就使用shadowColor
自己的透明度实蔽;而如果shadowColor
是不透明的,陰影的透明度就使用paint
的透明度谨读。
2.7 setMaskFilter(MaskFilter maskfilter)
為之后的繪制設(shè)置 MaskFilter
局装。上一個方法 setShadowLayer()
是設(shè)置的在繪制層下方的附加效果;而這個 MaskFilter
和它相反劳殖,設(shè)置的是在繪制層上方的附加效果铐尚。
到現(xiàn)在已經(jīng)有兩個
setXxxFilter(filter)
了。前面有一個setColorFilter(filter)
哆姻,是對每個像素的顏色進(jìn)行過濾宣增;而這里的setMaskFilter(filter)
則是基于整個畫面來進(jìn)行過濾。
MaskFilter
有兩種: BlurMaskFilter
和 EmbossMaskFilter
矛缨。
2.7.1 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)部不繪制泌霍,外部模糊(什么鬼?)
2.7.2 EmbossMaskFilter
浮雕效果的 MaskFilter
述召。
paint.setMaskFilter(new 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
是一個 3 個元素的數(shù)組蟹地,指定了光源的方向; ambient
是環(huán)境光的強度藤为,數(shù)值范圍是 0 到 1锈津; specular
是炫光的系數(shù); blurRadius
是應(yīng)用光線的范圍凉蜂。
不過由于我沒有在項目中使用過 EmbossMaskFilter
琼梆,對它的每個參數(shù)具體調(diào)節(jié)方式并不熟,你有興趣的話自己研究一下吧窿吩。
2.8 獲取繪制的 Path
這是效果類的最后一組方法茎杂,也是效果類唯一的一組 get
方法。
這組方法做的事是纫雁,根據(jù) paint
的設(shè)置煌往,計算出繪制 Path
或文字時的實際 Path。
這里你可能會冒出兩個問題:
- 什么叫「實際
Path
」轧邪?Path
就是Path
刽脖,這加上個「實際」是什么意思? - 文字的
Path
忌愚?文字還有Path
曲管?
這兩個問題(咦好像有四個問號)的答案就在后面的內(nèi)容里。
2.8.1 getFillPath(Path src, Path dst)
首先解答第一個問題:「實際 Path
」硕糊。所謂實際 Path
院水,指的就是 drawPath()
的繪制內(nèi)容的輪廓,要算上線條寬度和設(shè)置的 PathEffect
简十。
默認(rèn)情況下(線條寬度為 0檬某、沒有 PathEffect
),原 Path
和實際 Path
是一樣的螟蝙;而在線條寬度不為 0 (并且模式為 STROKE
模式或 FLL_AND_STROKE
)恢恼,或者設(shè)置了 PathEffect
的時候,實際 Path
就和原 Path
不一樣了:
看明白了嗎胰默?
通過 getFillPath(src, dst)
方法就能獲取這個實際 Path
场斑。方法的參數(shù)里,src
是原 Path
初坠,而 dst
就是實際 Path
的保存位置和簸。 getFillPath(src, dst)
會計算出實際 Path
彭雾,然后把結(jié)果保存在 dst
里碟刺。
2.8.2 getTextPath(String text, int start, int end, float x, float y, Path path) / getTextPath(char[] text, int index, int count, float x, float y, Path path)
這里就回答第二個問題:「文字的 Path
」。文字的繪制薯酝,雖然是使用 Canvas.drawText()
方法半沽,但其實在下層爽柒,文字信息全是被轉(zhuǎn)化成圖形,對圖形進(jìn)行繪制的者填。 getTextPath()
方法浩村,獲取的就是目標(biāo)文字所對應(yīng)的 Path
。這個就是所謂「文字的 Path
」占哟。
這兩個方法心墅, getFillPath()
和 getTextPath()
,就是獲取繪制的 Path
的方法榨乎。之所以把它們歸類到「效果」類方法怎燥,是因為它們主要是用于圖形和文字的裝飾效果的位置計算,比如自定義的下劃線效果蜜暑。
到此為止铐姚, Paint
的第二類方法——效果類,就也介紹完了肛捍。
3 drawText() 相關(guān)
Paint
有些設(shè)置是文字繪制相關(guān)的隐绵,即和 drawText()
相關(guān)的。
比如設(shè)置文字大凶竞痢:
比如設(shè)置文字間隔:
比如設(shè)置各種文字效果:
除此之外依许,Paint
還有很多與文字繪制相關(guān)的設(shè)置或計算的方法,非常詳細(xì)缀蹄。不過由于太詳細(xì)了悍手,相關(guān)方法太多了(Paint
超過一半的方法都是 drawText()
相關(guān)的,算不算多袍患?)坦康,如果放在這里講它們的話,內(nèi)容會顯得有點過量诡延。所以這一節(jié)我就不講它們了滞欠,把它們放在下一節(jié)里單獨講。
4 初始化類
這一類方法很簡單肆良,它們是用來初始化 Paint
對象筛璧,或者是批量設(shè)置 Paint
的多個屬性的方法。
4.1 reset()
重置 Paint
的所有屬性為默認(rèn)值惹恃。相當(dāng)于重新 new
一個夭谤,不過性能當(dāng)然高一些啦。
4.2 set(Paint src)
把 src
的所有屬性全部復(fù)制過來巫糙。相當(dāng)于調(diào)用 src
所有的 get
方法朗儒,然后調(diào)用這個 Paint
的對應(yīng)的 set
方法來設(shè)置它們。
4.3 setFlags(int flags)
批量設(shè)置 flags。相當(dāng)于依次調(diào)用它們的 set
方法醉锄。例如: ???
paint.setFlags(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
這行代碼乏悄,和下面這兩行是等價的:
paint.setAntiAlias(true);
paint.setDither(true);
setFlags(flags)
對應(yīng)的 get
方法是 int getFlags()
。
好了恳不,這些就是 Paint
的四類方法:顏色類檩小、效果類、文字繪制相關(guān)以及初始化類烟勋。其中顏色類规求、效果類和初始化類都已經(jīng)在這節(jié)里面講過了,剩下的一類——文字繪制類卵惦,下一節(jié)單獨講颓哮。
最后再強調(diào)一遍:這期的內(nèi)容沒必要全部背會,只要看懂鸵荠、理解冕茅,記住有這么個東西就行了。以后在用到的時候蛹找,再拐回來翻一翻就行了姨伤。
練習(xí)項目
為了避免轉(zhuǎn)頭就忘,強烈建議你趁熱打鐵庸疾,做一下這個練習(xí)項目:HenCoderPracticeDraw2
下期預(yù)告
下期是文字繪制專場乍楚,我將會花一整期的篇幅來詳述文字的繪制。慣例放出部分配圖作為預(yù)覽: