画布的相关操作也是十分重要的,上一篇《自定义view绘图篇–Paint与Canvas》的总结使我们对绘图有了一些基本的概念,并且能够绘制了基本的几何图形,本节继续深入,探讨画布的相关操作。
本节要点
一、画布平移 (translate)
1、画布须知
画布的默认大小、默认坐标系和你的自定义view的大小、自定义view的坐标系一致!!!
画布的默认大小、默认坐标系和你的自定义view的大小、自定义view的坐标系一致!!!
画布的默认大小、默认坐标系和你的自定义view的大小、自定义view的坐标系一致!!!
重要的事说三遍哈。。。
ps:画布的坐标系我们看成虚拟的就行,他只影响你的作画。
(1)栗子
(2)佐证
2、画布的平移操作
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GRAY);
paint.setColor(Color.RED);
canvas.drawCircle(0, 0, 100, paint); // 坐标原点为圆心画圆
paint.setColor(Color.BLUE);
canvas.translate(100, 100); //移动画布 使画布的坐标系圆心为view坐标系中的(100,100)这点
canvas.drawCircle(0, 0, 100, paint); // 画布圆心画圆
}
(2)画出平移后的坐标系
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.YELLOW);
canvas.translate(100, 100); //移动画布 使画布的坐标系圆心为view坐标系中的(100,100)这点
canvas.drawCircle(0, 0, 100, paint); // 画布圆心画圆
paint.setColor(Color.RED);
canvas.drawLines(lines, paint);
}
如上:我们可以虚拟出画布的坐标,红线向右为正,向下为正。
二、画布缩放 (scale)
1、方法
方法1:
sx 、sy 为x轴y轴缩放比例。
方法2:
sx 、sy 为x轴y轴缩放比例。
px、py 为中心点的坐标(控制中心点的位置)
2、缩放参数sx 、sy 的取值范围
sx 、sy取值范围 (-∞,+∞)
1、缩放比例和view动画的缩放比例取值类似,就是缩放的倍数
2、注意当为负数时,代表缩放相应的倍数后,再沿着中心翻转
3、数值为0,图案消失
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.YELLOW);
canvas.translate(100, 100); //移动画布 使画布的坐标系圆心为view坐标系中的(100,100)这点
canvas.drawCircle(0, 0, 100, paint); // 画布圆心画圆
paint.setColor(Color.RED);
canvas.drawLines(lines, paint);
paint.setColor(Color.RED);
canvas.scale(.5f, .5f); //缩放画布为原来的一般
canvas.drawCircle(0, 0, 100, paint);// 画圆
}
3、缩放经典案例
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(300, 300); //移动画布 使画布的坐标系圆心为view坐标系中的(100,100)这点
paint.setColor(Color.RED);
canvas.drawLines(lines, paint); // 画个平移后画布的坐标系
paint.setColor(Color.BLACK);
canvas.drawCircle(0, 0, 200, paint); // 画布圆心画圆
for (int i = 0; i < 30; i++) {
canvas.scale(.9f, .9f); //缩放画布为原来的一般
canvas.drawCircle(0, 0, 200, paint);// 画圆
}
}
注意:和平移一样,缩放是可以叠加的,如上每次把画布缩放为原来的0.9倍。循环30次即可得到上图。
三、画布旋转 (rotate)
1、方法
public void rotate (float degrees)
public final void rotate (float degrees, float px, float py)
方法1参数:degrees画布旋转角度
方法2参数:degrees画布旋转角度,px、py 指定画布的中心点。
2、简单的钟表时针刻度实战
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(300, 300); //移动画布 使画布的坐标系圆心为view坐标系中的(300,300)这点
paint.setColor(Color.RED);
canvas.drawLines(lines, paint); // 画个平移后画布的坐标系
paint.setColor(Color.BLACK);
canvas.drawCircle(0, 0, 200, paint); // 画布圆心画圆
for (int i = 0; i < 12; i++) {
//画布相对上次旋转12次
canvas.rotate(30);
canvas.drawLine(0, 200, 0, 180, paint);
}
}
须知:和画布的平移、缩放一样,画布的旋转也是可叠加的
思路:
1、先画圆(这里半径设置200)
2、画一个0点的线(这里线长度为200-180=20)
3、让画布每次旋转30度,旋转12次即可
ps:没接触过canvas相关操作,给你个自定义时钟需求这些思路我们可能想不到,这里知识积累到后,自己就想摸索出来了。快乐啦。。。。
四、画布扭曲(错切、斜切) skew
1、正切回顾
2、方法
/**
* Preconcat the current matrix with the specified skew.
*
* @param sx The amount to skew in X
* @param sy The amount to skew in Y
*/
public void skew(float sx, float sy)
参数:
1、sx:将画布在x轴倾斜n°后的tan n°的值即 sx=tan n°
2、sy:将画布在y轴倾斜n°后的tan n°的值即 sy=tan n°
ps:比如我们sx参数填1.732 (根号3)就是x轴大约倾斜了60°
3、栗子
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.translate(300, 300); //1、移动画布 使画布的坐标系圆心为view坐标系中的(100,100)这点
paint.setColor(Color.RED);
canvas.drawLines(lines, paint); // 2、画个平移后画布的坐标系
paint.setColor(Color.BLACK);
canvas.drawRect(0, 0, 200,200, paint); // 3、画个矩形
paint.setColor(Color.GREEN);
canvas.skew(1.732f,0);
canvas.drawRect(0, 0, 200,200, paint); // 4、扭曲画布后再画个矩形
}
五 、画布的裁剪 (ClipXxx)
画布裁剪顾名思义就是在画布上裁剪出一块小的画布
具体的说就是利用ClipXxx相关的函数在画布上裁剪出 rect、Path、Region等。
1、ClipXxx相关的方法
boolean clipPath(Path path)
boolean clipPath(Path path, Region.Op op)
boolean clipRect(Rect rect, Region.Op op)
boolean clipRect(RectF rect, Region.Op op)
boolean clipRect(int left, int top, int right, int bottom)
boolean clipRect(float left, float top, float right, float bottom)
boolean clipRect(RectF rect)
boolean clipRect(float left, float top, float right, float bottom, Region.Op op)
boolean clipRect(Rect rect)
boolean clipRegion(Region region)
boolean clipRegion(Region region, Region.Op op)
这里引用:自定义控件之绘图篇(四):canvas变换与操作-五的内容,由于api都差不多自己就不下啦,偷偷懒。。。。。
2、栗子
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GRAY); //互补背景设置为灰色
canvas.clipRect(0,0,300,300);
canvas.drawColor(Color.WHITE); // 裁剪的小画布设置为白色背景
canvas.drawCircle(150,150,50,paint); //圆心为(150,150)半径为50 画圆
}
六、画布的保存与恢复 (save、 restore)
前面的相关操作:旋转、平移、缩放、扭曲、等操作后是可以叠加的。比如我们把画布平移后,以后的绘制图案操作都是基于平移后的。这就比价不尽人意啦,我们想要下次还操作之前的画布呢?这是安卓提供了save和restore方法
1、方法
- save() 保存当前状态,入栈。
- restore()取出栈顶的状态
2、栗子:
(1)未进行状态恢复时
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GRAY); //画布背景设置为灰色
canvas.save(); // 1、保存下画布的状态 状态入栈
canvas.clipRect(0,0,300,300); // 裁剪画布
canvas.drawColor(Color.WHITE); // 画布设置为白色背景
canvas.drawCircle(300,300,50,paint); // 基于裁剪过得画布内画圆
}
可以看出我们的操作是基于裁剪之后的画布(超出裁剪的区域绘制不出来的)
(2)恢复上次保存的状态
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GRAY); //画布背景设置为灰色
canvas.save(); // 1、保存下画布的状态 状态入栈
canvas.clipRect(0,0,300,300); // 裁剪画布
canvas.drawColor(Color.WHITE); // 画布设置为白色背景
canvas.drawCircle(300,300,50,paint); // 基于裁剪过得画布内画圆
//恢复裁剪之前保存的状态
canvas.restore();
canvas.drawCircle(300,300,50,paint); // 读取上次save时的画布状态
}
3、注意
每次save就相当于状态入栈一次,具有多次save时,一定要注意你restore的状态是哪一次的。
小结
通过对画布的探讨总结,明白了一些技巧,比如自定义闹钟以后就有思路啦。。。知识在慢慢积累内心也有成就感!快乐啦马飞飞。。。。。溜溜球下篇见。
下一篇:自定义view绘图篇–Path
参考文章: