Canvas 意為畫(huà)布,對(duì)于自定義 View 而言,有了畫(huà)布,就有了世界。
| 操作 | API | 備注 |
|---|---|---|
| 繪制顏色 | drawColor, drawRGB, drawARGB | 使用單一顏色填充整個(gè)畫(huà)布 |
| 繪制形狀 | drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc | 點(diǎn)、線(xiàn)、矩形、圓角矩形、橢圓、圓、圓弧 |
| 繪制文本 | drawText, drawPosText, drawTextOnPath | 繪制文字、繪制文字時(shí)指定每個(gè)文字位置、根據(jù)路徑繪制文字 |
一、新建自定義 View
- 新建 Java 類(lèi),并繼承 View
- 重寫(xiě)構(gòu)造器
- 在構(gòu)造器中做初始化工作
public class TView extends View {
private Paint mPaint;
//一個(gè)參數(shù)的構(gòu)造器在代碼中動(dòng)態(tài)構(gòu)建的時(shí)候會(huì)被調(diào)用
public TView(Context context) {
super(context);
initPaint();
}
//兩個(gè)參數(shù)的構(gòu)造器在初始化 xml 中的控件時(shí)會(huì)被調(diào)用
public TView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initPaint();
}
private void initPaint() {
mPaint = new Paint(); //新建畫(huà)筆
mPaint.setColor(Color.BLACK); //顏色
mPaint.setStrokeCap(Paint.Cap.ROUND); //點(diǎn)形狀,不設(shè)置為方形
mPaint.setStyle(Paint.Style.FILL); //填充方式
mPaint.setStrokeWidth(10f); //粗細(xì)
}
}
二、繪制點(diǎn)
三個(gè)方法:
drawPoint(float x, float y, Paint paint)
drawPoints(float[] pts, Paint paint);
drawPoints(float[] pts, int offset, int count,Paint paint)
通過(guò)上面的方法,在 onDraw 方法中繪制點(diǎn)(重寫(xiě) View 的 onDraw 方法):
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPoint(200,500,mPaint);
canvas.drawPoint(200,600,mPaint);
canvas.drawPoint(200,700,mPaint);
mPaint.setColor(Color.RED);
canvas.drawPoints(new float[]{
400,500,
400,600,
400,700
}
,mPaint);
mPaint.setColor(Color.BLUE);
//第二個(gè)參數(shù)為跳過(guò)前幾個(gè)數(shù)據(jù),第三個(gè)參數(shù)為數(shù)組長(zhǎng)度
canvas.drawPoints(new float[]{
600,500,
600,600,
600,700,
600,800,
600,900
},2,10,mPaint);
}

三、繪制線(xiàn)
三個(gè)方法:
drawPoint(float x, float y, Paint paint)
drawPoints(float[] pts, Paint paint);
drawPoints(float[] pts, int offset, int count,Paint paint)
和繪制點(diǎn)不同的是,第三個(gè)方法中,count 參數(shù)為 pts 除去 offset 值剩下的元素個(gè)數(shù),且值為 4 的倍數(shù),否則是會(huì)拋錯(cuò)的。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawLine(200,100,300,100,mPaint);
mPaint.setColor(Color.RED);
canvas.drawLines(new float[]{
200,200,400,200,
200,300,500,300,
},mPaint);
mPaint.setColor(Color.BLUE);
canvas.drawLines(new float[]{
600,300,700,300,
600,400,800,400,
600,500,900,500
},4,8,mPaint);
}

四、繪制圓
一個(gè)方法:
drawCircle(float cx, float cy, float radius, @NonNull Paint paint)
繪制方法比較簡(jiǎn)單,只要把圓心坐標(biāo)和半徑填入,就可以按照預(yù)定的畫(huà)筆繪制。這里需要注意的是,繪制時(shí)根據(jù)畫(huà)筆的 Style 不同,圓形的實(shí)際大小會(huì)有所不同。
mPaint.setStyle(Paint.Style.FILL);
canvas.drawCircle(500,1000,50,mPaint);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(500,1200,50,mPaint);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawCircle(500,1400,50,mPaint);
mPaint.setColor(Color.RED);
mPaint.setStrokeWidth(2);

根據(jù)效果圖可以看到,Style 為 Paint.Style.FILL 時(shí),繪制時(shí)是不會(huì)把畫(huà)筆粗細(xì)算進(jìn)去的。
五、繪制矩形
三個(gè)方法:
drawRect(Rect r, Paint paint)
drawRect(RectF rect, Paint paint)
drawRect(float left, float top, float right, float bottom, Paint paint)
繪制一個(gè)矩形需要這個(gè)矩形對(duì)角兩個(gè)點(diǎn)的坐標(biāo),第一第二種方法原理也是相同的,不過(guò)把兩個(gè)坐標(biāo)封裝到了各自的類(lèi)中。Rect 和 RectF 在本質(zhì)上區(qū)別不是很大,除了精度不同外,功能是一樣的。
下面用三種方法分別繪制
/**繪制矩形*/
canvas.drawRect(100,100,700,300,mPaint);
mPaint.setColor(Color.RED);
Rect rect = new Rect(100,400,700,600);
canvas.drawRect(rect,mPaint);
mPaint.setColor(Color.BLUE);
RectF rectF = new RectF(100,700,700,900);
canvas.drawRect(rectF,mPaint);

六、繪制圓角矩形
兩個(gè)方法:
drawRoundRect(RectF rect, float rx, float ry, Paint paint)
drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, Paint paint)
上面第二種方法是在 API 21 才加入,所以一般繪制時(shí),我們會(huì)選擇第一種方式繪制。
繪制圓角矩形的參數(shù)和繪制矩形相比,多了兩個(gè)參數(shù): rx ry,這兩個(gè)參數(shù)是圓弧 x 軸上的半徑和 y 軸上的半徑。我們可以利用這兩個(gè)參數(shù)繪制一個(gè)橢圓。
RectF rect = new RectF(100, 100, 700, 300);
// rx 為矩形長(zhǎng)的一半,ry 為矩形寬的一半
canvas.drawRoundRect(rect,300,100,mPaint);
mPaint.setColor(Color.BLUE);
RectF rect2 = new RectF(100,400,700,600);
canvas.drawRoundRect(rect2,20,20,mPaint);

七、繪制橢圓
兩個(gè)方法:
drawOval(RectF rect, float rx, float ry, Paint paint)
drawOval(float left, float top, float right, float bottom, float rx, float ry, Paint paint)
同樣的,上面第二種方法是在 API 21 才加入,所以一般繪制時(shí),我們會(huì)選擇第一種方式繪制。
實(shí)際上,繪制橢圓和繪制矩形的 api 幾乎是一樣的用法,我們用相同的參數(shù)分別繪制橢圓和矩形:

可以看到,這個(gè)橢圓實(shí)際上是矩形的內(nèi)切,這樣就不難理解上面的參數(shù)了。
八、繪制圓弧
兩個(gè)方法
drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
同樣的,上面第二種方法是在 API 21 才加入,所以一般繪制時(shí),我們會(huì)選擇第一種方式繪制。
繪制圓弧的前四個(gè)參數(shù)和橢圓是一樣的,startAngle 和 sweepAngle 分別為開(kāi)始角度和掃過(guò)的角度,參數(shù)中需要我們注意的是 useCenter??磮D

可能換成填充方式看得更明白一些:

由圖可以看到,userCenter 表示圓弧是否與圓心連接,當(dāng) userCenter 為 true 的時(shí)候,形成的是一個(gè)由弧形和圓心圍成的扇形,當(dāng) userCenter 為 false 時(shí),形成的是圓弧和兩個(gè)端點(diǎn)圍成的圖形。
Canvas 的圖形繪制基本就是以上,通過(guò)不同的圖形組合,我們已經(jīng)可以做一些常見(jiàn)的自定義 View ,例如進(jìn)度條等等。
真的,不難。