自定義View 1-2Paint詳解

Paint 屬性分類

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

1 顏色

Canvas 繪制的內(nèi)容挎扰,有三層對(duì)顏色的處理:


image.png

1.1 基本顏色

1.1.1 直接設(shè)置顏色

1.1.1.1 setColor(int color)
paint.setColor(Color.parseColor("#009688"));  
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);  
image.png
1.1.1.2 setARGB(int a, int r, int g, int b)

和 setColor(color) 都是一樣一樣兒的翠订,只是它的參數(shù)用的是更直接的三原色與透明度的值巢音。實(shí)際運(yùn)用中,setColor() 和 setARGB() 哪個(gè)方便和順手用哪個(gè)吧蕴轨。

1.1.2 setShader(Shader shader) 設(shè)置 Shader

  • 著色器不是 Android 獨(dú)有的港谊,它是圖形領(lǐng)域里一個(gè)通用的概念,它和直接設(shè)置顏色的區(qū)別是橙弱,著色器設(shè)置的是一個(gè)顏色方案歧寺,或者說是一套著色規(guī)則。
  • 當(dāng)設(shè)置了 Shader 之后棘脐,Paint 在繪制圖形和文字時(shí)就不使用 setColor/ARGB() 設(shè)置的顏色了斜筐,而是使用 Shader 的方案中的顏色。
  • 在 Android 的繪制里使用 Shader 蛀缝,并不直接用 Shader 這個(gè)類顷链,而是用它的幾個(gè)子類。具體來講有 LinearGradient RadialGradient SweepGradient BitmapShader ComposeShader 這么幾個(gè):
1.1.2.1 LinearGradient 線性漸變

設(shè)置兩個(gè)點(diǎn)和兩種顏色屈梁,以這兩個(gè)點(diǎn)作為端點(diǎn)嗤练,使用兩種顏色的漸變來繪制顏色。

就像這樣:

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);  
image.png

構(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 (夾子模式革答??曙强?算了這個(gè)詞我不會(huì)翻)會(huì)在端點(diǎn)之外延續(xù)端點(diǎn)處的顏色残拐;MIRROR 是鏡像模式;REPEAT 是重復(fù)模式碟嘴。具體的看一下例子就明白溪食。

CLAMP:


image.png

MIRROR:


image.png

REPEAT:


image.png
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);  
image.png

構(gòu)造方法:
RadialGradient(float centerX, float centerY, float radius, int centerColor, int edgeColor, TileMode tileMode)臀防。

參數(shù):
centerX centerY:輻射中心的坐標(biāo)
radius:輻射半徑
centerColor:輻射中心的顏色
edgeColor:輻射邊緣的顏色
tileMode:輻射范圍之外的著色模式眠菇。

TileMode 類型和LinearGradient的TitleMode是一樣的

1.1.2.3 SweepGradient 掃描漸變

掃描漸變

Shader shader = new SweepGradient(300, 300, Color.parseColor("#E91E63"),  
        Color.parseColor("#2196F3"));
paint.setShader(shader);

...

canvas.drawCircle(300, 300, 200, paint);  
image.png

構(gòu)造方法:
SweepGradient(float cx, float cy, int color0, int color1)

參數(shù):
cx cy :掃描的中心
color0:掃描的起始顏色
color1:掃描的終止顏色

1.1.2.4 BitmapShader

用 Bitmap 來著色(終于不是漸變了)。其實(shí)也就是用 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);  
image.png

看著跟 Canvas.drawBitmap() 好像案ぶ浴捎废?事實(shí)上也是一樣的效果。如果你想繪制圓形的 Bitmap致燥,就別用 drawBitmap() 了登疗,改用 drawCircle() + BitmapShader 就可以了(其他形狀同理)。
構(gòu)造方法:
BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)

參數(shù):
bitmap:用來做模板的 Bitmap 對(duì)象
tileX:橫向的 TileMode
tileY:縱向的 TileMode。

1.1.2.5 ComposeShader 混合著色器

兩個(gè) Shader 一起使用

// 第一個(gè) Shader:頭像的 Bitmap
Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.batman);  
Shader shader1 = new BitmapShader(bitmap1, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

// 第二個(gè) Shader:從上到下的線性漸變(由透明到黑色)
Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.batman_logo);  
Shader shader2 = new BitmapShader(bitmap2, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

// ComposeShader:結(jié)合兩個(gè) Shader
Shader shader = new ComposeShader(shader1, shader2, PorterDuff.Mode.SRC_OVER);  
paint.setShader(shader);

...

canvas.drawCircle(300, 300, 300, paint);  

ComposeShader() 在硬件加速下是不支持兩個(gè)相同類型的 Shader 的辐益,所以這里也需要關(guān)閉硬件加速才能看到效果断傲。


image.png

構(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效果认罩,講解

1.2 setColorFilter(ColorFilter colorFilter)

為繪制設(shè)置顏色過濾。顏色過濾的意思续捂,就是為繪制的內(nèi)容設(shè)置一個(gè)統(tǒng)一的過濾策略垦垂,然后 Canvas.drawXXX() 方法會(huì)對(duì)每個(gè)像素都進(jìn)行過濾后再繪制出來。

舉幾個(gè)現(xiàn)實(shí)中比較常見的顏色過濾的例子:

  • 有色光照射:


    image.png
  • 有色玻璃透視:


    image.png
  • 膠卷:


    image.png

在 Paint 里設(shè)置 ColorFilter 牙瓢,使用的是 Paint.setColorFilter(ColorFilter filter) 方法劫拗。
ColorFilter 并不直接使用,而是使用它的子類矾克。它共有三個(gè)子類:LightingColorFilter PorterDuffColorFilter 和 ColorMatrixColorFilter页慷。

1.2.1 LightingColorFilter

這個(gè) LightingColorFilter 是用來模擬簡(jiǎn)單的光照效果的。

LightingColorFilter 的構(gòu)造方法是 LightingColorFilter(int mul, int add) 胁附,參數(shù)里的 mul 和 add 都是和顏色值格式相同的 int 值酒繁,其中 mul 用來和目標(biāo)像素相乘,add 用來和目標(biāo)像素相加:

R' = R * mul.R / 0xff + add.R  
G' = G * mul.G / 0xff + add.G  
B' = B * mul.B / 0xff + add.B  

效果:


image.png

image.png

1.2.2 PorterDuffColorFilter

作用是使用一個(gè)指定的顏色和一種指定的 PorterDuff.Mode 來與繪制對(duì)象進(jìn)行合成控妻。

它的構(gòu)造方法是 PorterDuffColorFilter(int color, PorterDuff.Mode mode) 其中的 color 參數(shù)是指定的顏色欲逃, mode 參數(shù)是指定的 Mode。同樣也是 PorterDuff.Mode 饼暑,不過和 ComposeShader 不同的是,PorterDuffColorFilter 作為一個(gè) ColorFilter洗做,只能指定一種顏色作為源弓叛,而不是一個(gè) Bitmap。

1.2.3 ColorMatrixColorFilter

ColorMatrixColorFilter 使用一個(gè) ColorMatrix 來對(duì)顏色進(jìn)行處理诚纸。 ColorMatrix 這個(gè)類撰筷,內(nèi)部是一個(gè) 4x5 的矩陣:

[ a, b, c, d, e,
  f, g, h, i, j,
  k, l, m, n, o,
  p, q, r, s, t ]

通過計(jì)算, ColorMatrix 可以把要繪制的像素進(jìn)行轉(zhuǎn)換畦徘。
效果:


matrixColorFilter.gif

1.3 setXfermode(Xfermode xfermode)

  • "Xfermode" 其實(shí)就是 "Transfer mode"毕籽,用 "X" 來代替 "Trans" 是一些美國(guó)人喜歡用的簡(jiǎn)寫方式
  • 以繪制的內(nèi)容作為源圖像,以 View 中已有的內(nèi)容作為目標(biāo)圖像井辆,選取一個(gè) PorterDuff.Mode 作為繪制內(nèi)容的顏色處理方案关筒。

效果:


image.png

創(chuàng)建 Xfermode 的時(shí)候其實(shí)是創(chuàng)建的它的子類 PorterDuffXfermode。而事實(shí)上杯缺,Xfermode 也只有這一個(gè)子類蒸播。所以在設(shè)置 Xfermode 的時(shí)候不用多想,直接用 PorterDuffXfermode 吧。
「只有一個(gè)子類袍榆?胀屿??什么設(shè)計(jì)包雀?」
實(shí)在更早的 Android 版本中宿崭,Xfermode 還有別的子類,但別的子類現(xiàn)在已經(jīng) deprecated 了才写,如今只剩下了 PorterDuffXfermode葡兑。所以目前它的使用看起來好像有點(diǎn)啰嗦,但其實(shí)是由于歷史遺留問題琅摩。

Xfermode 注意事項(xiàng)

1. 使用離屏緩沖(Off-screen Buffer)
  • Canvas.saveLayer()
    saveLayer() 可以做短時(shí)的離屏緩沖铁孵。使用方法很簡(jiǎn)單,在繪制代碼的前后各加一行代碼房资,在繪制之前保存蜕劝,繪制之后恢復(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); // 用完及時(shí)清除 Xfermode


canvas.restoreToCount(saved);
2. 控制好透明區(qū)域

使用 Xfermode 來繪制的內(nèi)容,除了注意使用離屏緩沖轰异,還應(yīng)該注意控制它的透明區(qū)域不要太小岖沛,要讓它足夠覆蓋到要和它結(jié)合繪制的內(nèi)容,否則得到的結(jié)果很可能不是你想要的搭独。

2 效果

效果類的 API 婴削,指的就是抗鋸齒、填充/輪廓牙肝、線條寬度等等這些唉俗。

2.1 setAntiAlias (boolean aa) 設(shè)置抗鋸齒

抗鋸齒在上一節(jié)已經(jīng)講過了,話不多說配椭,直接上圖:


image.png

另外虫溜,除了 setAntiAlias(aa) 方法,打開抗鋸齒還有一個(gè)更方便的方式:構(gòu)造方法股缸。創(chuàng)建 Paint 對(duì)象的時(shí)候衡楞,構(gòu)造方法的參數(shù)里加一個(gè) ANTI_ALIAS_FLAG 的 flag,就可以在初始化的時(shí)候就開啟抗鋸齒敦姻。

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);  
image.png

STROKE


image.png

FILL_AND_STROKE


image.png

2.3 線條形狀

設(shè)置線條形狀的一共有 4 個(gè)方法:setStrokeWidth(float width), setStrokeCap(Paint.Cap cap), setStrokeJoin(Paint.Join join), setStrokeMiter(float miter) 镰惦。

2.3.1 setStrokeWidth(float width)

image.png

2.3.2 setStrokeCap(Paint.Cap cap)

設(shè)置線頭的形狀缸浦。線頭形狀有三種:BUTT 平頭诲宇、ROUND 圓頭、SQUARE 方頭。默認(rèn)為 BUTT骡澈。

image.png

2.3.3 setStrokeJoin(Paint.Join join)

設(shè)置拐角的形狀。有三個(gè)值可以選擇:MITER 尖角、 BEVEL 平角和 ROUND 圓角。默認(rèn)為 MITER沮协。

image.png

2.3.4 setStrokeMiter(float miter)

這個(gè)方法是對(duì)于 setStrokeJoin() 的一個(gè)補(bǔ)充,它用于設(shè)置 MITER 型拐角的延長(zhǎng)線的最大值卓嫂。所謂「延長(zhǎng)線的最大值」慷暂,是這么一回事:

當(dāng)線條拐角為 MITER 時(shí),拐角處的外緣需要使用延長(zhǎng)線來補(bǔ)償:


image.png

而這種補(bǔ)償方案會(huì)有一個(gè)問題:如果拐角的角度太小晨雳,就有可能由于出現(xiàn)連接點(diǎn)過長(zhǎng)的情況行瑞。比如這樣:

image.png

所以為了避免意料之外的過長(zhǎng)的尖角出現(xiàn), MITER 型連接點(diǎn)有一個(gè)額外的規(guī)則:當(dāng)尖角過長(zhǎng)時(shí)餐禁,自動(dòng)改用 BEVEL 的方式來渲染連接點(diǎn)血久。例如上圖的這個(gè)尖角,在默認(rèn)情況下是不會(huì)出現(xiàn)的帮非,而是會(huì)由于延長(zhǎng)線過長(zhǎng)而被轉(zhuǎn)為 BEVEL 型連接點(diǎn):


image.png

2.4 色彩優(yōu)化

Paint 的色彩優(yōu)化有兩個(gè)方法: setDither(boolean dither) 和 setFilterBitmap(boolean filter) 氧吐。它們的作用都是讓畫面顏色變得更加「順眼」,但原理和使用場(chǎng)景是不同的末盔。

2.4.1 setDither(boolean dither)

設(shè)置圖像的抖動(dòng)筑舅。

所謂抖動(dòng)(注意,它就叫抖動(dòng)陨舱,不是防抖動(dòng)翠拣,也不是去抖動(dòng),有些人在翻譯的時(shí)候自作主張地加了一個(gè)「防」字或者「去」字游盲,這是不對(duì)的)误墓,是指把圖像從較高色彩深度(即可用的顏色數(shù))向較低色彩深度的區(qū)域繪制時(shí),在圖像中有意地插入噪點(diǎn)益缎,通過有規(guī)律地?cái)_亂圖像來讓圖像對(duì)于肉眼更加真實(shí)的做法优烧。

例子:
比如向 1 位色彩深度的區(qū)域中繪制灰色,由于 1 位深度只包含黑和白兩種顏色链峭,在默認(rèn)情況下,即不加抖動(dòng)的時(shí)候又沾,只能選擇向上或向下選擇最接近灰色的白色或黑色來繪制弊仪,那么顯示出來也只能是一片白或者一片黑。而加了抖動(dòng)后杖刷,就可以繪制出讓肉眼識(shí)別為灰色的效果了:

瞇著眼看這幅圖


image.png
image.png
2.4.2 setFilterBitmap(boolean filter)

設(shè)置是否使用雙線性過濾來繪制 Bitmap 励饵。

圖像在放大繪制的時(shí)候,默認(rèn)使用的是最近鄰插值過濾滑燃,這種算法簡(jiǎn)單役听,但會(huì)出現(xiàn)馬賽克現(xiàn)象;而如果開啟了雙線性過濾,就可以讓結(jié)果圖像顯得更加平滑典予。效果依然盜維基百科的圖:

image.png

2.5 setPathEffect(PathEffect effect)

使用 PathEffect 來給圖形的輪廓設(shè)置效果甜滨。對(duì) Canvas 所有的圖形繪制有效,也就是 drawLine() drawCircle() drawPath() 這些方法瘤袖。大概像這樣:

PathEffect pathEffect = new DashPathEffect(new float[]{10, 5}, 10);  
paint.setPathEffect(pathEffect);

...

canvas.drawCircle(300, 300, 200, paint);  
image.png

下面就具體說一下 Android 中的 6 種 PathEffect衣摩。PathEffect 分為兩類,單一效果的 CornerPathEffect DiscretePathEffect DashPathEffect PathDashPathEffect 捂敌,和組合效果的 SumPathEffect ComposePathEffect艾扮。

2.5.1 CornerPathEffect

把所有拐角變成圓角。

PathEffect pathEffect = new CornerPathEffect(20);

image.png

它的構(gòu)造方法 CornerPathEffect(float radius) 的參數(shù) radius 是圓角的半徑占婉。

2.5.2 DiscretePathEffect

把線條進(jìn)行隨機(jī)的偏離泡嘴,讓輪廓變得亂七八糟。亂七八糟的方式和程度由參數(shù)決定逆济。
PathEffect pathEffect = new DiscretePathEffect(20, 5);

image.png

DiscretePathEffect 具體的做法是酌予,把繪制改為使用定長(zhǎng)的線段來拼接,并且在拼接的時(shí)候?qū)β窂竭M(jìn)行隨機(jī)偏離纹腌。它的構(gòu)造方法 DiscretePathEffect(float segmentLength, float deviation) 的兩個(gè)參數(shù)中霎终, segmentLength 是用來拼接的每個(gè)線段的長(zhǎng)度, deviation 是偏離量升薯。這兩個(gè)值設(shè)置得不一樣莱褒,顯示效果也會(huì)不一樣,具體的你自己多試幾次就明白了涎劈,這里不再貼更多的圖广凸。

2.5.3 DashPathEffect

使用虛線來繪制線條。


image.png

它的構(gòu)造方法 DashPathEffect(float[] intervals, float phase) 中蛛枚, 第一個(gè)參數(shù) intervals 是一個(gè)數(shù)組谅海,它指定了虛線的格式:數(shù)組中元素必須為偶數(shù)(最少是 2 個(gè)),按照「畫線長(zhǎng)度蹦浦、空白長(zhǎng)度扭吁、畫線長(zhǎng)度、空白長(zhǎng)度」……的順序排列盲镶,例如上面代碼中的 20, 5, 10, 5 就表示虛線是按照「畫 20 像素侥袜、空 5 像素、畫 10 像素溉贿、空 5 像素」的模式來繪制枫吧;第二個(gè)參數(shù) phase 是虛線的偏移量。

2.5.4 PathDashPathEffect

這個(gè)方法比 DashPathEffect 多一個(gè)前綴 Path 宇色,所以顧名思義九杂,它是使用一個(gè) Path 來繪制「虛線」颁湖。具體看圖吧:

image.png

它的構(gòu)造方法 PathDashPathEffect(Path shape, float advance, float phase, PathDashPathEffect.Style style) 中, shape 參數(shù)是用來繪制的 Path 例隆; advance 是兩個(gè)相鄰的 shape 段之間的間隔甥捺,不過注意,這個(gè)間隔是兩個(gè) shape 段的起點(diǎn)的間隔裳擎,而不是前一個(gè)的終點(diǎn)和后一個(gè)的起點(diǎn)的距離涎永; phase 和 DashPathEffect 中一樣,是虛線的偏移鹿响;最后一個(gè)參數(shù) style羡微,是用來指定拐彎改變的時(shí)候 shape 的轉(zhuǎn)換方式。style 的類型為 PathDashPathEffect.Style 惶我,是一個(gè) enum 妈倔,具體有三個(gè)值:

  • TRANSLATE:位移
  • ROTATE:旋轉(zhuǎn)
  • MORPH:變體


    image.png

2.5.5 SumPathEffect

這是一個(gè)組合效果類的 PathEffect 。它的行為特別簡(jiǎn)單绸贡,就是分別按照兩種 PathEffect 分別對(duì)目標(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);  
image.png

2.5.6 ComposePathEffect

這也是一個(gè)組合效果類的 PathEffect 。不過它是先對(duì)目標(biāo) Path 使用一個(gè) PathEffect听怕,然后再對(duì)這個(gè)改變后的 Path 使用另一個(gè) PathEffect捧挺。

PathEffect pathEffect = new DashPathEffect(new float[]{10, 5}, 10);  
paint.setPathEffect(pathEffect);

...

canvas.drawCircle(300, 300, 200, paint);  
image.png

它的構(gòu)造方法 ComposePathEffect(PathEffect outerpe, PathEffect innerpe) 中的兩個(gè) PathEffect 參數(shù), innerpe 是先應(yīng)用的尿瞭, outerpe 是后應(yīng)用的闽烙。所以上面的代碼就是「先偏離,再變虛線」声搁。而如果把兩個(gè)參數(shù)調(diào)換黑竞,就成了「先變虛線,再偏離」疏旨。至于具體的視覺效果……我就不貼圖了很魂,你自己試試看吧!

總結(jié)

上面這些就是 Paint 中的 6 種 PathEffect檐涝。它們有的是有獨(dú)立效果的遏匆,有的是用來組合不同的 PathEffect 的,功能各不一樣谁榜。

注意: PathEffect 在有些情況下不支持硬件加速拉岁,需要關(guān)閉硬件加速才能正常使用:
Canvas.drawLine() 和 Canvas.drawLines() 方法畫直線時(shí),setPathEffect() 是不支持硬件加速的惰爬;
PathDashPathEffect 對(duì)硬件加速的支持也有問題撕瞧,所以當(dāng)使用 PathDashPathEffect 的時(shí)候,最好也把硬件加速關(guān)了胖替。

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);  
image.png

效果就是上面這樣招狸。方法的參數(shù)里, radius 是陰影的模糊范圍; dx dy 是陰影的偏移量信柿; shadowColor 是陰影的顏色稠曼。

如果要清除陰影層漠吻,使用 clearShadowLayer() 扔傅。

注意:

  • 在硬件加速開啟的情況下试读, setShadowLayer() 只支持文字的繪制,文字之外的繪制必須關(guān)閉硬件加速才能正常繪制陰影银亲。
  • 如果 shadowColor 是半透明的哄辣,陰影的透明度就使用 shadowColor 自己的透明度毅弧;而如果 shadowColor 是不透明的,陰影的透明度就使用 paint 的透明度。

2.7 setMaskFilter(MaskFilter maskfilter)

上一個(gè)方法 setShadowLayer() 是設(shè)置的在繪制層下方的附加效果;而這個(gè) MaskFilter 和它相反赶掖,設(shè)置的是在繪制層上方的附加效果颈走。

到現(xiàn)在已經(jīng)有兩個(gè) setXxxFilter(filter) 了司致。前面有一個(gè) setColorFilter(filter) 枣耀,是對(duì)每個(gè)像素的顏色進(jìn)行過濾;而這里的 setMaskFilter(filter) 則是基于整個(gè)畫面來進(jìn)行過濾。

MaskFilter 有兩種: BlurMaskFilter 和 EmbossMaskFilter。

2.7.1 BlurMaskFilter

模糊效果的 MaskFilter。

paint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.NORMAL));

...

canvas.drawBitmap(bitmap, 100, 100, paint);  
image.png

它的構(gòu)造方法 BlurMaskFilter(float radius, BlurMaskFilter.Blur style) 中掂恕, radius 參數(shù)是模糊的范圍, style 是模糊的類型。一共有四種:

  • NORMAL: 內(nèi)外都模糊繪制
  • SOLID: 內(nèi)部正常繪制,外部模糊
  • INNER: 內(nèi)部模糊逾柿,外部不繪制
  • OUTER: 內(nèi)部不繪制父腕,外部模糊(什么鬼斥难?)
image.png

2.7.2 EmbossMaskFilter

浮雕效果的 MaskFilter竞阐。

paint.setMaskFilter(new EmbossMaskFilter(new float[]{0, 1, 1}, 0.2f, 8, 10));

...

canvas.drawBitmap(bitmap, 100, 100, paint);  
image.png

它的構(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)用光線的范圍。

2.8 獲取繪制的 Path

根據(jù) paint 的設(shè)置劳翰,計(jì)算出繪制 Path 或文字時(shí)的實(shí)際 Path敦锌。

2.8.1 getFillPath(Path src, Path dst)

所謂實(shí)際 Path ,指的就是 drawPath() 的繪制內(nèi)容的輪廓佳簸,要算上線條寬度和設(shè)置的 PathEffect乙墙。

默認(rèn)情況下(線條寬度為 0、沒有 PathEffect)生均,原 Path 和實(shí)際 Path 是一樣的听想;而在線條寬度不為 0 (并且模式為 STROKE 模式或 FLL_AND_STROKE ),或者設(shè)置了 PathEffect 的時(shí)候马胧,實(shí)際 Path 就和原 Path 不一樣了:

image.png

通過 getFillPath(src, dst) 方法就能獲取這個(gè)實(shí)際 Path汉买。方法的參數(shù)里,src 是原 Path 佩脊,而 dst 就是實(shí)際 Path 的保存位置蛙粘。 getFillPath(src, dst) 會(huì)計(jì)算出實(shí)際 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)

文字的繪制出牧,雖然是使用 Canvas.drawText() 方法,但其實(shí)在下層抱冷,文字信息全是被轉(zhuǎn)化成圖形崔列,對(duì)圖形進(jìn)行繪制的。 getTextPath() 方法,獲取的就是目標(biāo)文字所對(duì)應(yīng)的 Path 赵讯。這個(gè)就是所謂「文字的 Path」盈咳。

image.png

這兩個(gè)方法, getFillPath()getTextPath() 边翼,就是獲取繪制的 Path 的方法鱼响。之所以把它們歸類到「效果」類方法,是因?yàn)樗鼈冎饕怯糜趫D形和文字的裝飾效果的位置計(jì)算组底,比如自定義的下劃線效果丈积。

image

到此為止, Paint 的第二類方法——效果類债鸡,就也介紹完了江滨。

3 drawText() 相關(guān)

Paint 有些設(shè)置是文字繪制相關(guān)的,即和 drawText() 相關(guān)的厌均。
比如設(shè)置文字大谢;:


image.png

比如設(shè)置文字間隔:


image.png

比如設(shè)置各種文字效果:


image.png

除此之外,Paint 還有很多與文字繪制相關(guān)的設(shè)置或計(jì)算的方法棺弊,非常詳細(xì)晶密。不過由于太詳細(xì)了,相關(guān)方法太多了(Paint 超過一半的方法都是 drawText() 相關(guān)的模她,算不算多稻艰?),如果放在這里講它們的話侈净,內(nèi)容會(huì)顯得有點(diǎn)過量尊勿。所以這一節(jié)我就不講它們了,把它們放在下一節(jié)里單獨(dú)講畜侦。

4 初始化類

這一類方法很簡(jiǎn)單运怖,它們是用來初始化 Paint 對(duì)象,或者是批量設(shè)置 Paint 的多個(gè)屬性的方法夏伊。

4.1 reset()

重置 Paint 的所有屬性為默認(rèn)值摇展。相當(dāng)于重新 new 一個(gè),不過性能當(dāng)然高一些啦溺忧。

4.2 set(Paint src)

把 src 的所有屬性全部復(fù)制過來咏连。相當(dāng)于調(diào)用 src 所有的 get 方法,然后調(diào)用這個(gè) Paint 的對(duì)應(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);
這行代碼歌溉,和下面這兩行是等價(jià)的:

paint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.NORMAL));

...

canvas.drawBitmap(bitmap, 100, 100, paint);  

參考:

https://hencoder.com/ui-1-2/
注意:本文全部摘自上面的鏈接垄懂,本人只是對(duì)上面鏈接內(nèi)容的自我抽取骑晶,符合本人閱讀

注意

最后再強(qiáng)調(diào)一遍:這期的內(nèi)容沒必要全部背會(huì),只要看懂草慧、理解桶蛔,記住有這么個(gè)東西就行了。以后在用到的時(shí)候漫谷,再拐回來翻一翻就行了仔雷。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市舔示,隨后出現(xiàn)的幾起案子碟婆,更是在濱河造成了極大的恐慌,老刑警劉巖惕稻,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件竖共,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡俺祠,警方通過查閱死者的電腦和手機(jī)肘迎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锻煌,“玉大人,你說我怎么就攤上這事姻蚓∷挝啵” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵狰挡,是天一觀的道長(zhǎng)捂龄。 經(jīng)常有香客問我,道長(zhǎng)加叁,這世上最難降的妖魔是什么倦沧? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮它匕,結(jié)果婚禮上展融,老公的妹妹穿的比我還像新娘。我一直安慰自己豫柬,他們只是感情好告希,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著烧给,像睡著了一般燕偶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上础嫡,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天指么,我揣著相機(jī)與錄音,去河邊找鬼。 笑死伯诬,一個(gè)胖子當(dāng)著我的面吹牛晚唇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播姑廉,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼缺亮,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了桥言?” 一聲冷哼從身側(cè)響起萌踱,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎号阿,沒想到半個(gè)月后并鸵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扔涧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年园担,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枯夜。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡弯汰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出湖雹,到底是詐尸還是另有隱情咏闪,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布摔吏,位于F島的核電站鸽嫂,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏征讲。R本人自食惡果不足惜据某,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望诗箍。 院中可真熱鬧癣籽,春花似錦、人聲如沸滤祖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽氨距。三九已至桑逝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間俏让,已是汗流浹背楞遏。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工茬暇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人寡喝。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓糙俗,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親预鬓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子巧骚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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