内容来自:安卓自定义View进阶-Canvas之画布操作
translate是坐标系的移动,位移是基于当前位置移动,而不是每次基于屏幕左上角的(0,0)点移动
// 绘制矩形
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawRect(new Rect(0, 0, 200, 200), mPaint);
// 在坐标原点绘制一个黑色圆形
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.FILL);
canvas.translate(200, 200);
canvas.drawCircle(100, 100, 100, mPaint);
// 在坐标原点绘制一个蓝色圆形
mPaint.setColor(Color.BLUE);
canvas.translate(200,200);
canvas.drawCircle(0,0,100,mPaint);
缩放提供了两个方法,如下:
public void scale (float sx, float sy)
public final void scale (float sx, float sy, float px, float py)
缩放的中心默认为坐标原点,而缩放中心轴就是坐标轴,第二个方法的px
和py
,用来控制缩放中心位置
// 将坐标系原点移动到画布正中心
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);
和位移(translate)一样,缩放也是可以叠加的,如下的例子:
// 将坐标系原点移动到画布正中心
canvas.translate(mWidth / 2, mHeight / 2);
RectF rect = new RectF(-400,-400,400,400);
for (int i = 0; i < 20; i++) {
canvas.scale(0.9f, 0.9f);
canvas.drawRect(rect, mPaint);
}
旋转提供了两种方法:
public void rotate (float degrees)
public final void rotate (float degrees, float px, float py)
第二种方法多出来的两个参数依旧是控制旋转中心点的
默认的旋转中心依旧是坐标原点:
// 将坐标系原点移动到画布正中心
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);
同样旋转也可以叠加
// 将坐标系原点移动到画布正中心
canvas.translate(mWidth / 2, mHeight / 2);
canvas.drawCircle(0,0,400,mPaint); // 绘制两个圆形
canvas.drawCircle(0,0,380,mPaint);
for (int i=0; i<=360; i+=10){ // 绘制圆形之间的连接线
canvas.drawLine(0,380,0,400,mPaint);
canvas.rotate(10);
}
skew只提供了一种方法
public void skew (float sx, float sy)
sx
- 将画布在x
方向上倾斜相应的角度,sx倾斜角度的tan
值sy
- 将画布在y
轴方向上倾斜相应的角度,sy为倾斜角度的tan
值// 将坐标系原点移动到画布正中心
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);
我的理解,类似于iOS的CGContextSaveGState
和CGContextRestoreGState
相关API | 简介 |
---|---|
save | 把当前的画布的状态进行保存,然后放入特定的栈中 |
saveLayerXxx | 新建一个图层,并放入特定的栈中 |
restore | 把栈中最顶层的画布状态取出来,并按照这个状态恢复当前的画布 |
restoreToCount | 弹出指定位置及其以上所有的状态,并按照指定位置的状态进行恢复 |
getSaveCount | 获取栈中内容的数量(即保存次数) |
状态栈
状态栈可以存储画布状态和图层状态
save
save 有两种方法:
// 保存全部状态
public int save ()
// 根据saveFlags参数保存一部分状态
public int save (int saveFlags)
可以看到第二种方法比第一种多了一个saveFlags参数,使用这个参数可以只保存一部分状态,更加灵活。saveFlags
参数,参见下表
名称 | 简介 |
---|---|
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(); //保存状态
... //具体操作
restore(); //回滚到之前的状态