自定義 View基礎(三)

Paint 詳解

Paint 的 API 大致可以分為 4 類:

  • 顏色
  • 效果
  • drawText() 相關
  • 初始化

1 顏色

Canvas 繪制的內(nèi)容豆同,有三層對顏色的處理:


canvas_flow.png

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)

![1NI1{IN{FDBB[]M2{E4_WM.png

構造方法:
  • 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

9%JC85WB4VTO93Y2)QXJEHA.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 是應用光線的范圍导匣。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市茸时,隨后出現(xiàn)的幾起案子贡定,更是在濱河造成了極大的恐慌,老刑警劉巖可都,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缓待,死亡現(xiàn)場離奇詭異,居然都是意外死亡渠牲,警方通過查閱死者的電腦和手機命斧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嘱兼,“玉大人国葬,你說我怎么就攤上這事∏酆荆” “怎么了汇四?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長踢涌。 經(jīng)常有香客問我通孽,道長,這世上最難降的妖魔是什么睁壁? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任背苦,我火速辦了婚禮,結果婚禮上潘明,老公的妹妹穿的比我還像新娘行剂。我一直安慰自己,他們只是感情好钳降,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布厚宰。 她就那樣靜靜地躺著,像睡著了一般遂填。 火紅的嫁衣襯著肌膚如雪铲觉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天吓坚,我揣著相機與錄音撵幽,去河邊找鬼。 笑死礁击,一個胖子當著我的面吹牛盐杂,可吹牛的內(nèi)容都是我干的漏麦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼况褪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了更耻?” 一聲冷哼從身側響起测垛,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎秧均,沒想到半個月后食侮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡目胡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年锯七,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片誉己。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡眉尸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出巨双,到底是詐尸還是另有隱情噪猾,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布筑累,位于F島的核電站袱蜡,受9級特大地震影響,放射性物質發(fā)生泄漏慢宗。R本人自食惡果不足惜坪蚁,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望镜沽。 院中可真熱鬧敏晤,春花似錦、人聲如沸缅茉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宾舅。三九已至统阿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間筹我,已是汗流浹背扶平。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蔬蕊,地道東北人结澄。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親麻献。 傳聞我的和親對象是個殘疾皇子们妥,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355

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