Android自定义View——Canvas操作学习笔记

Posted by Csming on 2017-03-05

Canvas的基本操作

位移(translate)

translate是坐标系的移动,可以为图形绘制选择一个合适的坐标系

1
2
3
4
5
6
7
8
9
10
11
// 省略了创建画笔的代码

// 在坐标原点绘制一个黑色圆形
mPaint.setColor(Color.BLACK);
canvas.translate(200,200);
canvas.drawCircle(0,0,100,mPaint);

// 在坐标原点绘制一个蓝色圆形
mPaint.setColor(Color.BLUE);
canvas.translate(200,200);
canvas.drawCircle(0,0,100,mPaint);

缩放(Scale)

缩放有两种方法

1
2
3
public void scale (float sx, float sy)

public final void scale (float sx, float sy, float px, float py)

两个方法中前两个参数是相同的分别为x轴和y轴的缩放比例。而第二种方法比前一种多了两个参数,用来控制缩放中心位置的。

sx与sy取值

saveflages 简介
[-∞, -1) 先根据缩放中心放大n倍,再根据中心轴进行翻转
-1 根据缩放中心轴进行翻转
(-1, 0) 先根据缩放中心缩小到n,再根据中心轴进行翻转
0 不会显示,若sx为0,则宽度为0,不会显示,sy同理
(0, 1) 根据缩放中心缩小到n
1 没有变化
(1, +∞) 根据缩放中心放大n倍

eg:

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
canvas.translate(mWidth / 2, mHeight / 2);

RectF rect = new RectF(0,-400,400,0); // 矩形区域

mPaint.setColor(Color.BLACK); // 绘制黑色矩形
canvas.drawRect(rect,mPaint);

canvas.scale(0.5f,0.5f); // 画布缩放

mPaint.setColor(Color.BLUE); // 绘制蓝色矩形
canvas.drawRect(rect,mPaint);

// 将坐标系原点移动到画布正中心
canvas.translate(mWidth / 2, mHeight / 2);

RectF rect = new RectF(0,-400,400,0); // 矩形区域

mPaint.setColor(Color.BLACK); // 绘制黑色矩形
canvas.drawRect(rect,mPaint);

canvas.scale(0.5f,0.5f,200,0); // 画布缩放 <-- 缩放中心向右偏移了200个单位

mPaint.setColor(Color.BLUE); // 绘制蓝色矩形
canvas.drawRect(rect,mPaint);

// 将坐标系原点移动到画布正中心
canvas.translate(mWidth / 2, mHeight / 2);

RectF rect = new RectF(0,-400,400,0); // 矩形区域

mPaint.setColor(Color.BLACK); // 绘制黑色矩形
canvas.drawRect(rect,mPaint);


canvas.scale(-0.5f,-0.5f); // 画布缩放

mPaint.setColor(Color.BLUE); // 绘制蓝色矩形
canvas.drawRect(rect,mPaint);

// 将坐标系原点移动到画布正中心
canvas.translate(mWidth / 2, mHeight / 2);

RectF rect = new RectF(0,-400,400,0); // 矩形区域

mPaint.setColor(Color.BLACK); // 绘制黑色矩形
canvas.drawRect(rect,mPaint);

canvas.scale(-0.5f,-0.5f,200,0); // 画布缩放 <-- 缩放中心向右偏移了200个单位

mPaint.setColor(Color.BLUE); // 绘制蓝色矩形
canvas.drawRect(rect,mPaint);

scale可以叠加

旋转(rotate)

有两种方法

1
2
3
public void rotate (float degrees)

public final void rotate (float degrees, float px, float py)

和缩放一样,第二种方法多出来的两个参数依旧是控制旋转中心点的。

默认的旋转中心依旧是坐标原点

eg:

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
// 将坐标系原点移动到画布正中心
canvas.translate(mWidth / 2, mHeight / 2);

RectF rect = new RectF(0,-400,400,0); // 矩形区域

mPaint.setColor(Color.BLACK); // 绘制黑色矩形
canvas.drawRect(rect,mPaint);

canvas.rotate(180); // 旋转180度 <-- 默认旋转中心为原点

mPaint.setColor(Color.BLUE); // 绘制蓝色矩形
canvas.drawRect(rect,mPaint);

// 将坐标系原点移动到画布正中心
canvas.translate(mWidth / 2, mHeight / 2);

RectF rect = new RectF(0,-400,400,0); // 矩形区域

mPaint.setColor(Color.BLACK); // 绘制黑色矩形
canvas.drawRect(rect,mPaint);

canvas.rotate(180,200,0); // 旋转180度 <-- 旋转中心向右偏移200个单位

mPaint.setColor(Color.BLUE); // 绘制蓝色矩形
canvas.drawRect(rect,mPaint);

rotate可叠加

错切

1
public void skew (float sx, float sy)

float sx:将画布在x方向上倾斜相应的角度,sx倾斜角度的tan值,
float sy:将画布在y轴方向上倾斜相应的角度,sy为倾斜角度的tan值.

变换后:

X = x + sx * y
Y = sy * x + y

eg:

1
2
3
4
5
6
7
8
9
10
11
12
// 将坐标系原点移动到画布正中心
canvas.translate(mWidth / 2, mHeight / 2);

RectF rect = new RectF(0,0,200,200); // 矩形区域

mPaint.setColor(Color.BLACK); // 绘制黑色矩形
canvas.drawRect(rect,mPaint);

canvas.skew(1,0); // 水平错切 <- 45度

mPaint.setColor(Color.BLUE); // 绘制蓝色矩形
canvas.drawRect(rect,mPaint);

快照(save)和回滚(restore)

画布的操作是不可逆的,而且很多画布操作会影响后续的步骤,例如第一个例子,两个圆形都是在坐标原点绘制的,而因为坐标系的移动绘制出来的实际位置不同。所以会对画布的一些状态进行保存和回滚。

  • save把当前的画布的状态进行保存,然后放入特定的栈中

  • saveLayerXxx新建一个图层,并放入特定的栈中

  • restore把栈中最顶层的画布状态取出来,并按照这个状态恢复当前的画布

  • restoreToCount弹出指定位置及其以上所有的状态,并按照指定位置的状态进行恢复

  • getSaveCount获取栈中内容的数量(即保存次数)

  • **什么是画布和图层?**我们看到的画布是由多个图层构成的

我们的绘制操作和画布粗啊哦做都是在默认图层上进行的;
若要绘制比较复杂的内容,可以采用分图层;

  • save的方法:
1
2
3
4
5
// 保存全部状态
public int save ()

// 根据saveFlags参数保存一部分状态
public int save (int saveFlags)

saveflags:

saveflages 简介
ALL_SAVE_FLAG 默认,保存全部状态
CLIP_SAVE_FLAG 保存剪辑区
CLIP_TO_LAYER_SAVE_FLAG 剪裁区作为图层保存
FULL_COLOR_LAYER_SAVE_FLAG 保存图层的全部色彩通道
HAS_ALPHA_LAYER_SAVE_FLAG 保存图层的alpha(不透明度)通道
MATRIX_SAVE_FLAG 保存Matrix信息( translate, rotate, scale, skew)

每调用一次save方法,都会在栈顶添加一条状态信息;

  • saveLayerXxx方法
1
2
3
4
5
6
7
8
9
10
11
// 无图层alpha(不透明度)通道
public int saveLayer (RectF bounds, Paint paint)
public int saveLayer (RectF bounds, Paint paint, int saveFlags)
public int saveLayer (float left, float top, float right, float bottom, Paint paint)
public int saveLayer (float left, float top, float right, float bottom, Paint paint, int saveFlags)

// 有图层alpha(不透明度)通道
public int saveLayerAlpha (RectF bounds, int alpha)
public int saveLayerAlpha (RectF bounds, int alpha, int saveFlags)
public int saveLayerAlpha (float left, float top, float right, float bottom, int alpha)
public int saveLayerAlpha (float left, float top, float right, float bottom, int alpha, int saveFlags)
  • restore方法
    状态回滚;即从状态栈顶取出一个状态然后对内容进行恢复;

  • restoreToCount方法
    获取保存的次数,即状态栈中保存状态的数量

1
2
3
save();      //保存状态
... //具体操作
restore(); //回滚到之前的状态

出处:http://www.gcssloop.com/customview/Canvas_Convert