自定義View一:繪製-Paint

1、Paint類

自定義控件具有很強的靈活性,可以根據你的想法畫出各種各樣的圖案,在Android中如果是自定義控件的話,Paint這個類用的還是較多的,先來看一下這個類的註釋:

/**
 * The Paint class holds the style and color information about how to draw
 * geometries, text and bitmaps.
 */

使用保存的樣式和顏色信息,繪製幾何圖形,文本和bitmap。

2、Paint方法

mPaint.setColor(Color.RED);// 設置顏色
mPaint.setARGB(255, 255, 255, 0); // 設置 Paint對象顏色,範圍爲0~255
mPaint.setAlpha(200); // 設置alpha不透明度,範圍爲0~255
mPaint.setAntiAlias(true); // 抗鋸齒
mPaint.setStyle(Paint.Style.FILL); //描邊效果
mPaint.setStrokeWidth(4);//描邊寬度
mPaint.setStrokeCap(Paint.Cap.ROUND); //圓角效果
mPaint.setStrokeJoin(Paint.Join.MITER);//拐角風格
mPaint.setShader(new SweepGradient(200, 200, Color.BLUE, Color.RED)); //設置環形渲染器
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN)); //設置圖層混合模式
mPaint.setColorFilter(new LightingColorFilter(0x00ffff, 0x000000)); //設置顏色過濾器

3、線條形狀

3.1 Paint. setAntiAlias

設置抗鋸齒

3.2 Paint.Style

paint.setStyle(Paint.Style.FILL); //填充所有
paint.setStyle(Paint.Style.STROKE); //描邊效果,只畫出線條
paint.setStyle(Paint.Style.FILL_AND_STROKE); //填充內部和描邊

3.3 Paint.cap

paint.setStrokeCap(Paint.Cap.BUTT); //默認效果,如繪製的正方形,就是正方行
paint.setStrokeCap(Paint.Cap.ROUND); //繪製的圖形兩邊會有圓角效果,兩邊的圓角是在SQUARE 的基礎上延申出一部分形成圓角
paint.setStrokeCap(Paint.Cap.SQUARE); //BUTT 的基礎上,兩邊延申出去一部分

3.4 Paint.Join

paint.setStrokeJoin(Paint.Join.MITER);//拐角風格,直角
paint.setStrokeJoin(Paint.Join.BEVEL);//拐角風格,切割
paint.setStrokeJoin(Paint.Join.ROUND);//拐角風格,圓角

3.5 Paint. StrokeMiter

paint.setStrokeMiter(1.7f);

對於 setStrokeJoin() 的一個補充,它用於設置 MITER 型拐角的延長線的最大值。

4、drawBitmap

4.1 Paint.setXfermode

4.2 Paint.setDither

設置圖像的抖動

paint.setDither(true);

4.3 Paint.setFilterBitmap

是否使用雙線性過濾來繪製 Bitmap

圖像在放大繪製的時候,默認使用的是最近鄰插值過濾,這種算法簡單,但會出現馬賽克現象;而如果開啓了雙線性過濾,就可以讓結果圖像顯得更加平滑。

paint.setFilterBitmap(true);

5、drawText

5.1 Paint.Align

paint.setTextAlign(Paint.Align.LEFT);  //左對齊,默認
paint.setTextAlign(Paint.Align.CENTER);//居中對齊
paint.setTextAlign(Paint.Align.RIGHT); //右對齊

5.2 Paint.FontMetrics

字體的度量,是指對於指定字號的某種字體,在度量方面的各種屬性,其描述參數包括:

Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
float top = fontMetrics.top;
float ascent = fontMetrics.ascent;
float descent = fontMetrics.descent;
float bottom = fontMetrics.bottom;
float leading = fontMetrics.leading;

baseline:字符基線

ascent:字符最高點到baseline的推薦距離

top:字符最高點到baseline的最大距離

descent:字符最低點到baseline的推薦距離

bottom:字符最低點到baseline的最大距離

leading:行間距,即前一行的descent與下一行的ascent之間的距離

     參考:https://blog.csdn.net/flyeek/article/details/43934945

5.3 Paint.Measure

float[] measuredWidth = new float[16];
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
//字符的高度
float textHeight = fontMetrics.descent + Math.abs(fontMetrics.ascent);
//字符串的長度;
float textLength = mPaint.measureText(text);
//measuredWidth每一個字符的長度;textWidths字符數
int textWidths = mPaint.getTextWidths(text, measuredWidth);
//截取的最大距離中字符個數
int breakText = mPaint.breakText(text, true, 50, null);

breakText()這個方法:

/**
 * 計算出要截取的字符個數
 *
 * @param text            測量的字符串
 * @param start           測量開始的位置
 * @param end             測量結束的位置
 * @param measureForwards 測量方向,true從前往後,false從後往前
 * @param maxWidth        截取的字符串最大寬度
 * @param measuredWidth   截取字符串實際寬度
 * @return 需要截取的字符個數
 */
public int breakText(CharSequence text, int start, int end, 
                     boolean measureForwards, float maxWidth,
                     float[] measuredWidth);

5.4 Paint.setShadowLayer

mPaint.setShadowLayer(10, 10, 10, Color.RED);
canvas.drawText("ANDROID", 0, 100, mPaint);

注意:

在硬件加速開啓的情況下, setShadowLayer() 只支持文字的繪製,文字之外的繪製必須關閉硬件加速才能正常繪製陰影。

如果 shadowColor 是半透明的,陰影的透明度就使用 shadowColor 自己的透明度;而如果 shadowColor 是不透明的,陰影的透明度就使用 paint 的透明度。

6、PathEffect

使用 PathEffect 來給圖形的輪廓設置效果。

Android 中的 6 種 PathEffect:

單一效果: CornerPathEffect、DiscretePathEffect、DashPathEffect、PathDashPathEffect

組合效果:SumPathEffect ComposePathEffect

6.1 CornerPathEffect

把所有拐角變成圓角

PathEffect effect = new CornerPathEffect(60);
mPaint.setPathEffect(effect);
canvas.drawPath(mPath, mPaint);

6.2 DiscretePathEffect

把線條進行隨機的偏離,讓輪廓變得亂七八糟。

DiscretePathEffect 具體的做法是,把繪製改爲使用定長的線段來拼接,並且在拼接的時候對路徑進行隨機偏離。DiscretePathEffect(float segmentLength, float deviation) 的兩個參數中, segmentLength 是用來拼接的每個線段的長度, deviation 是偏離量。這兩個值設置得不一樣,顯示效果也會不一樣。

PathEffect effect = new DiscretePathEffect(20, 10);
mPaint.setPathEffect(effect);
canvas.drawPath(mPath, mPaint);

6.3 DashPathEffect

使用虛線來繪製線條。

它的構造方法 DashPathEffect(float[] intervals, float phase) 中, 第一個參數 intervals 是一個數組,它指定了虛線的格式:數組中元素必須爲偶數(最少是 2 個),按照「畫線長度、空白長度、畫線長度、空白長度」……的順序排列,例如上面代碼中的 20, 5, 10, 5 就表示虛線是按照「畫 20 像素、空 5 像素、畫 10 像素、空 5 像素」的模式來繪製;第二個參數 phase 是虛線的偏移量。

PathEffect effect = new DashPathEffect(new float[]{30,15,60, 15}, 10);
mPaint.setPathEffect(effect);
canvas.drawPath(mPath, mPaint);

6.4 PathDashPathEffect

這個方法比 DashPathEffect 多一個前綴 Path ,所以顧名思義,它是使用一個Path 來繪製「虛線」。

它的構造方法:PathDashPathEffect(Path shape, float advance, float phase, Style style );

PathDashPathE中, shape 參數是用來繪製的 Path ; advance 是兩個相鄰的 shape 段之間的間隔,不過注意,這個間隔是兩個 shape 段的起點的間隔,而不是前一個的終點和後一個的起點的距離; phase 和 DashPathEffect 中一樣,是虛線的偏移;最後一個參數 style,是用來指定拐彎改變的時候 shape 的轉換方式。style 的類型爲 PathDashPathEffect.Style ,是一個 enum ,具體有三個值:

TRANSLATE:位移

ROTATE:旋轉

MORPH:變體

Path shape = new Path();
shape.moveTo(0,20);
shape.lineTo(20,0);
shape.lineTo(40, 20);

PathEffect effect = new PathDashPathEffect(shape,50,40, PathDashPathEffect.Style.TRANSLATE);
mPaint.setPathEffect(effect);
canvas.drawRoundRect(0,0, 400,300, 72,72, mPaint);

6.5 SumPathEffect

這是一個組合效果類的 PathEffect 。它的行爲特別簡單,就是分別按照兩種PathEffect 分別對目標進行繪製。

PathEffect dashPathEffect = new DashPathEffect(new float[]{10, 10}, 10);
PathEffect discretePathEffect = new DiscretePathEffect(40, 20);
PathEffect sumPathEffect = new SumPathEffect(dashPathEffect, discretePathEffect);
mPaint.setPathEffect(sumPathEffect);
canvas.drawPath(mPath, mPaint);

6.6 ComposePathEffect

這也是一個組合效果類的 PathEffect 。不過它是先對目標 Path 使用一個PathEffect,然後再對這個改變後的 Path 使用另一個 PathEffect。

PathEffect dashPathEffect = new DashPathEffect(new float[]{10, 10}, 10);
PathEffect discretePathEffect = new DiscretePathEffect(40, 20);
PathEffect sumPathEffect = new ComposePathEffect(dashPathEffect, discretePathEffect);
mPaint.setPathEffect(sumPathEffect);
canvas.drawPath(mPath, mPaint);

它的構造方法ComposePathEffect(PathEffect outerpe, PathEffect innerpe) 中的兩個PathEffect 參數, innerpe 是先應用的, outerpe 是後應用的。所以上面的代碼就是「先偏離,再變虛線」。而如果把兩個參數調換,就成了「先變虛線,再偏離」。

7、MaskFilter

爲之後的繪製設置 MaskFilter。上一個方法 setShadowLayer() 是設置的在繪製層下方的附加效果;而這個 MaskFilter 和它相反,設置的是在繪製層上方的附加效果。

MaskFilter 有兩種: BlurMaskFilter 和 EmbossMaskFilter。

7.1 BlurMaskFilter

模糊效果

MaskFilter filter = new BlurMaskFilter(50, BlurMaskFilter.Blur.INNER);
mPaint.setMaskFilter(filter);
canvas.drawBitmap(bitmap, 100, 100, mPaint);

它的構造方法 BlurMaskFilter(float radius, BlurMaskFilter.Blur style)中, radius 參數是模糊的範圍, style 是模糊的類型。一共有四種:

NORMAL : 內外都模糊繪製

SOLID : 內部正常繪製,外部模糊

INNER : 內部模糊,外部不繪製

OUTER : 內部不繪製,外部模糊

7.2 EmbossMaskFilter

浮雕效果

EmbossMaskFilter (float[] direction,    // 3個浮點值的數組,X、Y、Z方向指定光源
                  float ambient,        // 環境光亮度,取值範圍是0~1
                  float specular,       // 反射等級,值如:8
                  float blurRadius)     // 照明前的模糊量,值如:3
MaskFilter filter = new EmbossMaskFilter(new float[]{-1, 1, -1}, 1f, 8, 3.5f);
mPaint.setMaskFilter(filter);
canvas.drawText("ANDROID", 0, 200, mPaint);

效果不是很明顯…

8.Shader

Shader 這個英文單詞很多人沒有見過,它的中文叫做「着色器」,也是用於設置繪製顏色的。在 Android 的繪製裏使用 Shader ,並不直接用 Shader 這個類,而是用它的幾個子類:

LinearGradient、RadialGradient、SweepGradient、BitmapShader、 ComposeShader

8.1 LinearGradient線性渲染

**
 * 1.線性渲染,LinearGradient(float x0, float y0, float x1, float y1, @NonNull @ColorInt int colors[], @Nullable float positions[], @NonNull TileMode tile)
 * (x0,y0):漸變起始點座標
 * (x1,y1):漸變結束點座標
 * colors:漸變數組
 * positions:位置數組,position的取值範圍[0,1],作用是指定某個位置的顏色值,如果傳null,漸變就線性變化。
 * tile:用於指定控件區域大於指定的漸變區域時,空白區域的顏色填充方法,分爲三種:CLAMP(最後1像素拉伸) REPEAT(重複) MIRROR(鏡影)
 */
//渲染一個x和y的座標點是(200, 100),顏色是從綠色到紅色漸變,在0.6f(60%)的時候開始漸變成紅色,1 最後是藍色 ,繪製區域大於渲染器指定區域的填充是1像素拉伸
Shader lineShader = new LinearGradient(0, 0, 200, 0,
        new int[]{Color.RED, Color.GREEN, Color.BLUE},
        new float[]{0, 0.6f, 1},
        Shader.TileMode.REPEAT);

8.2 RadialGradient環形渲染

/**
 * 環形渲染,RadialGradient(float centerX, float centerY, float radius, @ColorInt int colors[], @Nullable float stops[], TileMode tileMode)
 * centerX ,centerY:shader的中心座標,開始漸變的座標
 * radius:漸變的半徑
 * centerColor,edgeColor:中心點漸變顏色,邊界的漸變顏色
 * colors:漸變顏色數組
 * stoops:漸變位置數組,類似掃描漸變的positions數組,取值[0,1],中心點爲0,半徑到達位置爲1.0f
 * tileMode:shader未覆蓋以外的填充模式。
 */
Shader shader = new RadialGradient(200, 200, 130,
        new int[]{Color.GREEN, Color.YELLOW, Color.RED},
        null, Shader.TileMode.REPEAT);
mPaint.setShader(shader);

8.3 SweepGradient掃描渲染

/**
 * 掃描渲染,順時針方向逐漸漸變渲染 SweepGradient(float cx, float cy, @ColorInt int color0,int color1)
 * cx,cy 漸變中心座標
 * color0,color1:漸變開始結束顏色
 * colors,positions:類似LinearGradient,用於多顏色漸變,positions爲null時,根據顏色線性漸變
 */
Shader shader  = new SweepGradient(200, 200,
        new int[]{Color.RED, Color.GREEN, Color.BLUE},
        new float[]{0.5f, 0.3f,1});

8.4 BitmapShader位圖渲染

/** 
* 位圖渲染,BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY)
 * Bitmap:構造shader使用的bitmap
 * tileX:X軸方向的TileMode
 * tileY:Y軸方向的TileMode
            REPEAT, 繪製區域超過渲染區域的部分,重複排版
            CLAMP, 繪製區域超過渲染區域的部分,會以最後一個像素拉伸排版
            MIRROR, 繪製區域超過渲染區域的部分,鏡像翻轉排版
 */
Shader shader = new BitmapShader(mBitmap, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);

8.5 ComposeShader組合渲染

Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.flower);
Shader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);

LinearGradient linearGradient = new LinearGradient(0, 0, 200, 200,
        new int[]{Color.RED, Color.GREEN, Color.BLUE},
        null,
        Shader.TileMode.REPEAT);

Shader shader = new ComposeShader(bitmapShader, linearGradient, PorterDuff.Mode.MULTIPLY);
mPaint.setShader(shader);

9、ColorFilter

ColorFilter 這個類,它的名字已經足夠解釋它的作用:爲繪製設置顏色過濾。顏色過濾的意思,就是爲繪製的內容設置一個統一的過濾策略,然後Canvas.drawXXX() 方法會對每個像素都進行過濾後再繪製出來。

ColorFilter 並不直接使用,而是使用它的子類。它共有三個子類:LightingColorFilter、PorterDuffColorFilter 和 ColorMatrixColorFilter。

9.1 LightingColorFilter 光照效果

/**
 * 用來模擬簡單的光照效果 LightingColorFilter(@ColorInt int mul, @ColorInt int add)
 * mul:和目標像素相乘,默認0xffffff
 * add:和目標像素相加,默認0x000000
 * R' = R * mul.R / 0xff + add.R
 * G' = G * mul.G / 0xff + add.G
 * B' = B * mul.B / 0xff + add.B
 */
ColorFilter filter = new LightingColorFilter(0x00ffff, 0x000000);

如果你想去掉原像素中的紅色,可以把它的 mul 改爲 0x00ffff。綠色加強,可以把它的 add 改爲 0x003000。

9.2 PorterDuffColorFilter 混合濾鏡

/**
 * 使用一個指定的顏色和一種指定的 PorterDuff.Mode 來與繪製對象進行合成
 * PorterDuffColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode)
 * color: 指定的顏色
 * mode:指定的 Mode
 */
ColorFilter filter = new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY);

9.3 ColorMatrixColorFilter

/**
 * 使用一個 ColorMatrix 來對顏色進行處理。 ColorMatrix 這個類,內部是一個 4x5 的矩陣:
 * [ a, b, c, d, e,
 *   f, g, h, i, j,
 *   k, l, m, n, o,
 *   p, q, r, s, t ]
 * 對於顏色 [R, G, B, A] ,轉換算法是這樣的:
 *  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 colorMatrix = new ColorMatrix();
colorMatrix.setSaturation(0.5f);
//colorMatrix.setRotate(0, 90);
//colorMatrix.setScale(0.5f,0.5f,0.5f,0.5f);
ColorFilter filter = new ColorMatrixColorFilter(colorMatrix)

ColorMatrix 有一些自帶的方法可以做簡單的轉換,setSaturation(float sat) 來設置飽和度。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章