android中,如果我们想绘制复杂的自定义View或游戏,我们就需要熟悉绘图API。Android通过Canvas类暴露了很多drawXXX方法,我们可以通过这些方法绘制各种各样的图形。Canvas绘图有三个基本要素:Canvas、绘图坐标系以及Paint。Canvas是画布,我们通过Canvas的各种drawXXX方法将图形绘制到Canvas上面,在drawXXX方法中我们需要传入要绘制的图形的坐标形状,还要传入一个画笔Paint。drawXXX方法以及传入其中的坐标决定了要绘制的图形的形状,比如drawCircle方法,用来绘制圆形,需要我们传入圆心的x和y坐标,以及圆的半径。drawXXX方法中传入的画笔Paint决定了绘制的图形的一些外观,比如是绘制的图形的颜色,再比如是绘制圆面还是圆的轮廓线等。Android系统的设计吸收了很多已有系统的诸多优秀之处,比如Canvas绘图。Canvas不是Android所特有的,Flex和Silverlight都支持Canvas绘图,Canvas也是HTML5标准中的一部分,主流的现代浏览器都支持用JavaScript在Canvas上绘图,如果你用过HTML5中的Canvas,你会发现Android的Canvas的绘图API与其很相似。总之,Canvas绘图不是Android所特有的。
为了演示Android中各种drawXXX方法的时候,我做了一个App,通过单击相应的按钮绘制相应的图形,主界面如下所示:
Canvas绘图中牵扯到两种坐标系:Canvas坐标系与绘图坐标系。
为了更好的理解绘图坐标系,请看如下的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
//绘制坐标系
private
void
drawAxis(Canvas canvas){
int
canvasWidth = canvas.getWidth();
int
canvasHeight = canvas.getHeight();
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(
6
* density);
//用绿色画x轴,用蓝色画y轴
//第一次绘制坐标轴
paint.setColor(
0xff00ff00
);
//绿色
canvas.drawLine(
0
,
0
, canvasWidth,
0
, paint);
//绘制x轴
paint.setColor(
0xff0000ff
);
//蓝色
canvas.drawLine(
0
,
0
,
0
, canvasHeight, paint);
//绘制y轴
//对坐标系平移后,第二次绘制坐标轴
canvas.translate(canvasWidth /
4
, canvasWidth /
4
);
//把坐标系向右下角平移
paint.setColor(
0xff00ff00
);
//绿色
canvas.drawLine(
0
,
0
, canvasWidth,
0
, paint);
//绘制x轴
paint.setColor(
0xff0000ff
);
//蓝色
canvas.drawLine(
0
,
0
,
0
, canvasHeight, paint);
//绘制y轴
//再次平移坐标系并在此基础上旋转坐标系,第三次绘制坐标轴
canvas.translate(canvasWidth /
4
, canvasWidth /
4
);
//在上次平移的基础上再把坐标系向右下角平移
canvas.rotate(
30
);
//基于当前绘图坐标系的原点旋转坐标系
paint.setColor(
0xff00ff00
);
//绿色
canvas.drawLine(
0
,
0
, canvasWidth,
0
, paint);
//绘制x轴
paint.setColor(
0xff0000ff
);
//蓝色
canvas.drawLine(
0
,
0
,
0
, canvasHeight, paint);
//绘制y轴
}
|
第一次绘制绘图坐标系时,绘图坐标系默认情况下和Canvas坐标系重合,所以绘制出的坐标系紧贴View的上侧和左侧;
第二次首先将坐标轴向右下角平移了一段距离,然后绘制出的坐标系也就整体向右下角平移了;
第三次再次向右下角平移,并旋转了30度,图上倾斜的坐标系即最后的绘图坐标系。
Canvas中的drawARGB可以用来对整个Canvas以某种统一的颜色整体绘制,四个参数分别是Alpha、Red、Green、Blue,取值都是0-255。
使用代码如下:
1
2
3
|
private
void
drawARGB(Canvas canvas){
canvas.drawARGB(
255
,
139
,
197
,
186
);
}
|
Canvas中用drawText方法绘制文字,代码如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
private
void
drawText(Canvas canvas){
int
canvasWidth = canvas.getWidth();
int
halfCanvasWidth = canvasWidth /
2
;
float
translateY = textHeight;
//绘制正常文本
canvas.save();
canvas.translate(
0
, translateY);
canvas.drawText(
"正常绘制文本"
,
0
,
0
, paint);
canvas.restore();
translateY += textHeight *
2
;
//绘制绿色文本
paint.setColor(
0xff00ff00
);
//设置字体为绿色
canvas.save();
canvas.translate(
0
, translateY);
//将画笔向下移动
canvas.drawText(
"绘制绿色文本"
,
0
,
0
, paint);
canvas.restore();
paint.setColor(
0xff000000
);
//重新设置为黑色
translateY += textHeight *
2
;
//设置左对齐
paint.setTextAlign(Paint.Align.LEFT);
//设置左对齐
canvas.save();
canvas.translate(halfCanvasWidth, translateY);
canvas.drawText(
"左对齐文本"
,
0
,
0
, paint);
canvas.restore();
translateY += textHeight *
2
;
//设置居中对齐
paint.setTextAlign(Paint.Align.CENTER);
//设置居中对齐
canvas.save();
canvas.translate(halfCanvasWidth, translateY);
canvas.drawText(
"居中对齐文本"
,
0
,
0
, paint);
canvas.restore();
translateY += textHeight *
2
;
//设置右对齐
paint.setTextAlign(Paint.Align.RIGHT);
//设置右对齐
canvas.save();
canvas.translate(halfCanvasWidth, translateY);
canvas.drawText(
"右对齐文本"
,
0
,
0
, paint);
canvas.restore();
paint.setTextAlign(Paint.Align.LEFT);
//重新设置为左对齐
translateY += textHeight *
2
;
//设置下划线
paint.setUnderlineText(
true
);
//设置具有下划线
canvas.save();
canvas.translate(
0
, translateY);
canvas.drawText(
"下划线文本"
,
0
,
0
, paint);
canvas.restore();
paint.setUnderlineText(
false
);
//重新设置为没有下划线
translateY += textHeight *
2
;
//绘制加粗文字
paint.setFakeBoldText(
true
);
//将画笔设置为粗体
canvas.save();
canvas.translate(
0
, translateY);
canvas.drawText(
"粗体文本"
,
0
,
0
, paint);
canvas.restore();
paint.setFakeBoldText(
false
);
//重新将画笔设置为非粗体状态
translateY += textHeight *
2
;
//文本绕绘制起点顺时针旋转
canvas.save();
canvas.translate(
0
, translateY);
canvas.rotate(
20
);
canvas.drawText(
"文本绕绘制起点旋转20度"
,
0
,
0
, paint);
canvas.restore();
}
|
对以上代码进行一下说明:
Canvas中用drawPoint方法绘制点,代码如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
private
void
drawPoint(Canvas canvas){
int
canvasWidth = canvas.getWidth();
int
canvasHeight = canvas.getHeight();
int
x = canvasWidth /
2
;
int
deltaY = canvasHeight /
3
;
int
y = deltaY /
2
;
paint.setColor(
0xff8bc5ba
);
//设置颜色
paint.setStrokeWidth(
50
* density);
//设置线宽,如果不设置线宽,无法绘制点
//绘制Cap为BUTT的点
paint.setStrokeCap(Paint.Cap.BUTT);
canvas.drawPoint(x, y, paint);
//绘制Cap为ROUND的点
canvas.translate(
0
, deltaY);
paint.setStrokeCap(Paint.Cap.ROUND);
canvas.drawPoint(x, y, paint);
//绘制Cap为SQUARE的点
canvas.translate(
0
, deltaY);
paint.setStrokeCap(Paint.Cap.SQUARE);
canvas.drawPoint(x, y, paint);
}
|
下面对以上代码进行说明:
Canvas通过drawLine方法绘制一条线段,通过drawLines方法绘制多段线,使用代码如下所示:
下面对以上代码进行说明:
Canvas通过drawRect方法绘制矩形,使用代码如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
private
void
drawRect(Canvas canvas){
int
canvasWidth = canvas.getWidth();
int
canvasHeight = canvas.getHeight();
//默认画笔的填充色是黑色
int
left1 =
10
;
int
top1 =
10
;
int
right1 = canvasWidth /
3
;
int
bottom1 = canvasHeight /
3
;
canvas.drawRect(left1, top1, right1, bottom1, paint);
//修改画笔颜色
paint.setColor(
0xff8bc5ba
);
//A:ff,R:8b,G:c5,B:ba
int
left2 = canvasWidth /
3
*
2
;
int
top2 =
10
;
int
right2 = canvasWidth -
10
;
int
bottom2 = canvasHeight /
3
;
canvas.drawRect(left2, top2, right2, bottom2, paint);
}
|
其方法签名是drawRect(float left, float top, float right, float bottom, Paint paint),left和right表示矩形的左边和右边分别到绘图坐标系y轴正半轴的距离,top和bottom表示矩形的上边和下边分别到绘图坐标系x轴正半轴的距离。
Canvas中用drawCircle方法绘制圆形,使用代码如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
private
void
drawCircle(Canvas canvas){
paint.setColor(
0xff8bc5ba
);
//设置颜色
paint.setStyle(Paint.Style.FILL);
//默认绘图为填充模式
int
canvasWidth = canvas.getWidth();
int
canvasHeight = canvas.getHeight();
int
halfCanvasWidth = canvasWidth /
2
;
int
count =
3
;
int
D = canvasHeight / (count +
1
);
int
R = D /
2
;
//绘制圆
canvas.translate(
0
, D / (count +
1
));
canvas.drawCircle(halfCanvasWidth, R, R, paint);
//通过绘制两个圆形成圆环
//1. 首先绘制大圆
canvas.translate(
0
, D + D / (count +
1
));
canvas.drawCircle(halfCanvasWidth, R, R, paint);
//2. 然后绘制小圆,让小圆覆盖大圆,形成圆环效果
int
r = (
int
)(R *
0.75
);
paint.setColor(
0xffffffff
);
//将画笔设置为白色,画小圆
canvas.drawCircle(halfCanvasWidth, R, r, paint);
//通过线条绘图模式绘制圆环
canvas.translate(
0
, D + D / (count +
1
));
paint.setColor(
0xff8bc5ba
);
//设置颜色
paint.setStyle(Paint.Style.STROKE);
//绘图为线条模式
float
strokeWidth = (
float
)(R *
0.25
);
paint.setStrokeWidth(strokeWidth);
canvas.drawCircle(halfCanvasWidth, R, R, paint);
}
|
下面对以上代码进行说明:
Canvas中提供了drawOval方法绘制椭圆,其使用代码如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
private
void
drawOval(Canvas canvas){
int
canvasWidth = canvas.getWidth();
int
canvasHeight = canvas.getHeight();
float
quarter = canvasHeight /
4
;
float
left =
10
* density;
float
top =
0
;
float
right = canvasWidth - left;
float
bottom= quarter;
RectF rectF =
new
RectF(left, top, right, bottom);
//绘制椭圆形轮廓线
paint.setStyle(Paint.Style.STROKE);
//设置画笔为画线条模式
paint.setStrokeWidth(
2
* density);
//设置线宽
paint.setColor(
0xff8bc5ba
);
//设置线条颜色
canvas.translate(
0
, quarter /
4
);
canvas.drawOval(rectF, paint);
//绘制椭圆形填充面
paint.setStyle(Paint.Style.FILL);
//设置画笔为填充模式
canvas.translate(
0
, (quarter + quarter /
4
));
canvas.drawOval(rectF, paint);
//画两个椭圆,形成轮廓线和填充色不同的效果
canvas.translate(
0
, (quarter + quarter /
4
));
//1. 首先绘制填充色
paint.setStyle(Paint.Style.FILL);
//设置画笔为填充模式
canvas.drawOval(rectF, paint);
//绘制椭圆形的填充效果
//2. 将线条颜色设置为蓝色,绘制轮廓线
paint.setStyle(Paint.Style.STROKE);
//设置画笔为线条模式
paint.setColor(
0xff0000ff
);
//设置填充色为蓝色
canvas.drawOval(rectF, paint);
//设置椭圆的轮廓线
}
|
下面对以上代码进行说明:
Canvas中提供了drawArc方法用于绘制弧,这里的弧指两种:弧面和弧线,弧面即用弧围成的填充面,弧线即为弧面的轮廓线。其使用代码如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
private
void
drawArc(Canvas canvas){
int
canvasWidth = canvas.getWidth();
int
canvasHeight = canvas.getHeight();
int
count =
5
;
float
ovalHeight = canvasHeight / (count +
1
);
float
left =
10
* density;
float
top =
0
;
float
right = canvasWidth - left;
float
bottom= ovalHeight;
RectF rectF =
new
RectF(left, top, right, bottom);
paint.setStrokeWidth(
2
* density);
//设置线宽
paint.setColor(
0xff8bc5ba
);
//设置颜色
paint.setStyle(Paint.Style.FILL);
//默认设置画笔为填充模式
//绘制用drawArc绘制完整的椭圆
canvas.translate(
0
, ovalHeight / count);
canvas.drawArc(rectF,
0
,
360
,
true
, paint);
//绘制椭圆的四分之一,起点是钟表的3点位置,从3点绘制到6点的位置
canvas.translate(
0
, (ovalHeight + ovalHeight / count));
canvas.drawArc(rectF,
0
,
90
,
true
, paint);
//绘制椭圆的四分之一,将useCenter设置为false
canvas.translate(
0
, (ovalHeight + ovalHeight / count));
canvas.drawArc(rectF,
0
,
90
,
false
, paint);
//绘制椭圆的四分之一,只绘制轮廓线
paint.setStyle(Paint.Style.STROKE);
//设置画笔为线条模式
canvas.translate(
0
, (ovalHeight + ovalHeight / count));
canvas.drawArc(rectF,
0
,
90
,
true
, paint);
//绘制带有轮廓线的椭圆的四分之一
//1. 先绘制椭圆的填充部分
paint.setStyle(Paint.Style.FILL);
//设置画笔为填充模式
canvas.translate(
0
, (ovalHeight + ovalHeight / count));
canvas.drawArc(rectF,
0
,
90
,
true
, paint);
//2. 再绘制椭圆的轮廓线部分
paint.setStyle(Paint.Style.STROKE);
//设置画笔为线条模式
paint.setColor(
0xff0000ff
);
//设置轮廓线条为蓝色
canvas.drawArc(rectF,
0
,
90
,
true
, paint);
}
|
下面对以上代码进行说明:
public void drawArc (RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
Canvas通过drawPath方法可以绘制Path。那Path是什么呢?Path致以过来是路径的意思,在Android中,Path是一种线条的组合图形,其可以由直线、二次曲线、三次曲线、椭圆的弧等组成。Path既可以画线条,也可以画填充面。其使用代码如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|