Canvas之画布操作
来源:互联网 发布:安卓悬浮窗源码 编辑:程序博客网 时间:2024/06/04 18:26
版权声明:本人所有文章均采用 [知识共享 署名-非商业性使用-禁止演绎 4.0 国际 许可协议] 转载前请保证理解此协议,原文出处 :http://www.gcssloop.com/#blog
目录(?)[+]
Canvas之画布操作
作者微博: @GcsSloop
【本系列相关文章】
上一篇Canvas之绘制基本形状中我们了解了如何使用Canvas绘制基本图形,本次了解一些基本的画布操作。
本来想把画布操作放到后面部分的,但是发现很多图形绘制都离不开画布操作,于是先讲解一下画布的基本操作方法。
一.Canvas的常用操作速查表
二.Canvas基本操作
1.画布操作
为什么要有画布操作?
画布操作可以帮助我们用更加容易理解的方式制作图形。
例如: 从坐标原点为起点,绘制一个长度为20dp,与水平线夹角为30度的线段怎么做?
按照我们通常的想法(被常年训练出来的数学思维),就是先使用三角函数计算出线段结束点的坐标,然后调用drawLine即可。
然而这是否是被固有思维禁锢了?
假设我们先绘制一个长度为20dp的水平线,然后将这条水平线旋转30度,则最终看起来效果是相同的,而且不用进行三角函数计算,这样是否更加简单了一点呢?
合理的使用画布操作可以帮助你用更容易理解的方式创作你想要的效果,这也是画布操作存在的原因。
PS: 所有的画布操作都只影响后续的绘制,对之前已经绘制过的内容没有影响。
⑴位移(translate)
translate是坐标系的移动,可以为图形绘制选择一个合适的坐标系。
请注意,位移是基于当前位置移动,而不是每次基于屏幕左上角的(0,0)点移动,如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
我们首先将坐标系移动一段距离绘制一个圆形,之后再移动一段距离绘制一个圆形,两次移动是可叠加的。
⑵缩放(scale)
缩放提供了两个方法,如下:
- 1
- 2
- 3
- 1
- 2
- 3
这两个方法中前两个参数是相同的分别为x轴和y轴的缩放比例。而第二种方法比前一种多了两个参数,用来控制缩放中心位置的。
缩放比例(sx,sy)取值范围详解:
如果在缩放时稍微注意一下就会发现缩放的中心默认为坐标原点,而缩放中心轴就是坐标轴,如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
(为了更加直观,我添加了一个坐标系,可以比较明显的看出,缩放中心就是坐标原点)
接下来我们使用第二种方法让缩放中心位置稍微改变一下,如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
(图中用箭头指示的就是缩放中心。)
前面两个示例缩放的数值都是正数,按照表格中的说明,当缩放比例为负数的时候会根据缩放中心轴进行翻转,下面我们就来实验一下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
为了效果明显,这次我不仅添加了坐标系而且对矩形中几个重要的点进行了标注,具有相同字母标注的点是一一对应的。
由于本次未对缩放中心进行偏移,所有默认的缩放中心就是坐标原点,中心轴就是x轴和y轴。
本次缩放可以看做是先根据缩放中心(坐标原点)缩放到原来的0.5倍,然后分别按照x轴和y轴进行翻转。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
添加了这么多的辅助内容,希望大家能够看懂。
本次对缩放中心点y轴坐标进行了偏移,故中心轴也向右偏移了。
PS:和位移(translate)一样,缩放也是可以叠加的。
- 1
- 2
- 1
- 2
调用两次缩放则 x轴实际缩放为0.5x0.5=0.25 y轴实际缩放为0.5x0.1=0.05
下面我们利用这一特性制作一个有趣的图形。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
⑶旋转(rotate)
旋转提供了两种方法:
- 1
- 2
- 3
- 1
- 2
- 3
和缩放一样,第二种方法多出来的两个参数依旧是控制旋转中心点的。
默认的旋转中心依旧是坐标原点:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
改变旋转中心位置:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
好吧,旋转也是可叠加的
- 1
- 2
- 1
- 2
调用两次旋转,则实际的旋转角度为180+20=200度。
为了演示这一个效果,我做了一个不明觉厉的东西:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
⑷错切(skew)
skew这里翻译为错切,错切是特殊类型的线性变换。
错切只提供了一种方法:
- 1
- 1
参数含义:
float sx:将画布在x方向上倾斜相应的角度,sx倾斜角度的tan值,
float sy:将画布在y轴方向上倾斜相应的角度,sy为倾斜角度的tan值.
变换后:
- 1
- 2
- 1
- 2
示例:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
如你所想,错切也是可叠加的,不过请注意,调用次序不同绘制结果也会不同
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
⑸快照(save)和回滚(restore)
Q: 为什存在快照与回滚
A:画布的操作是不可逆的,而且很多画布操作会影响后续的步骤,例如第一个例子,两个圆形都是在坐标原点绘制的,而因为坐标系的移动绘制出来的实际位置不同。所以会对画布的一些状态进行保存和回滚。
与之相关的API:
下面对其中的一些概念和方法进行分析:
状态栈:
其实这个栈我也不知道叫什么名字,暂时叫做状态栈吧,它看起来像下面这样:
这个栈可以存储画布状态和图层状态。
Q:什么是画布和图层?
A:实际上我们看到的画布是由多个图层构成的,如下图(图片来自网络):
实际上我们之前讲解的绘制操作和画布操作都是在默认图层上进行的。
在通常情况下,使用默认图层就可满足需求,但是如果需要绘制比较复杂的内容,如地图(地图可以有多个地图层叠加而成,比如:政区层,道路层,兴趣点层)等,则分图层绘制比较好一些。
你可以把这些图层看做是一层一层的玻璃板,你在每层的玻璃板上绘制内容,然后把这些玻璃板叠在一起看就是最终效果。
SaveFlags
save
save 有两种方法:
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
可以看到第二种方法比第一种多了一个saveFlags参数,使用这个参数可以只保存一部分状态,更加灵活,这个saveFlags参数具体可参考上面表格中的内容。
每调用一次save方法,都会在栈顶添加一条状态信息,以上面状态栈图片为例,再调用一次save则会在第5次上面载添加一条状态。
saveLayerXxx
saveLayerXxx有比较多的方法:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
注意:saveLayerXxx方法会让你花费更多的时间去渲染图像(图层多了相互之间叠加会导致计算量成倍增长),使用前请谨慎,如果可能,尽量避免使用。
使用saveLayerXxx方法,也会将图层状态也放入状态栈中,同样使用restore方法进行恢复。
这个暂时不过多讲述,如果以后用到详细讲解。(因为这里面东西也有不少啊QAQ)
restore
状态回滚,就是从栈顶取出一个状态然后根据内容进行恢复。
同样以上面状态栈图片为例,调用一次restore方法则将状态栈中第5次取出,根据里面保存的状态进行状态恢复。
restoreToCount
弹出指定位置以及以上所有状态,并根据指定位置状态进行恢复。
以上面状态栈图片为例,如果调用restoreToCount(2) 则会弹出 2 3 4 5 的状态,并根据第2次保存的状态进行恢复。
getSaveCount
获取保存的次数,即状态栈中保存状态的数量,以上面状态栈图片为例,使用该函数的返回值为5。
不过请注意,该函数的最小返回值为1,即使弹出了所有的状态,返回值依旧为1,代表默认状态。
常用格式
虽然关于状态的保存和回滚啰嗦了不少,不过大多数情况下只需要记住下面的步骤就可以了:
- 1
- 2
- 3
- 1
- 2
- 3
这种方式也是最简单和最容易理解的使用方法。
三.总结
如本文一开始所说,合理的使用画布操作可以帮助你用更容易理解的方式创作你想要的效果。
(,,• ₃ •,,)
PS: 由于本人英文水平有限,某些地方可能存在误解或词语翻译不准确,如果你对此有疑问可以提交Issues进行反馈。
About Me
作者微博: @GcsSloop
四.参考资料
Canvas
canvas变换与操作
Canvas之translate、scale、rotate、skew方法讲解
Canvas的save(),saveLayer()和restore()浅谈
Graphics->Layers
- Canvas之画布操作
- Canvas之画布操作
- android开发 之 Canvas之画布操作
- 自定义View进阶-Canvas之画布操作
- 自定义View进阶-Canvas之画布操作
- Android 画布Canvas之控件连线操作
- HTML5之画布Canvas
- JavaScript之Canvas画布
- canvas 之旋转画布
- 自定义View之Canvas之画布操作(转载)-6
- 安卓自定义View进阶-Canvas之画布操作
- 安卓自定义View进阶-Canvas之画布操作
- 安卓自定义View-Canvas之画布操作
- Android自定义View高级(三)-Canvas之画布操作
- 安卓自定义View进阶-Canvas之画布操作
- canvas画布中视图操作
- UGUI之Canvas(画布)
- Canvas画布
- 构建用户画像
- JavaScript之正则表达式去除换行符
- Java 开发环境配置
- get请求乱码 编码解码
- 从头到尾解析Hash 表算法
- Canvas之画布操作
- 《概率机器人》学习笔记一
- 【批处理脚本】遍历文件夹内所有文件名到txt文件
- Redis和Memcached对比
- mysql group_concat
- 欢迎使用CSDN-markdown编辑器
- Python 中的<>和!= 区别
- 数学建模课后习题
- 特征选择常用算法综述