canvas的常见用法
Canvas
canvas是一种抽象概念,是2D图形系统中的重要部分,canvas一系列函数最终都是android 2D图形库Skia的一些列封装,对应在SKCanvas.cpp。canvas在系统中的位置如下图所示
可以将canvas看成一个透明的图层,使用canvas之后会产生一个透明图层,然后在这个新图层上画图,画完之后覆盖在屏幕上显示,叠加。
比较经典的例子就是
` protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//构造一个矩形
Rect rect1 = new Rect(0, 0, 400, 220);
//在平移画布前用绿色画下边框
canvas.drawRect(rect1, paint_green);
//平移画布后,再用红色边框重新画下这个矩形
canvas.translate(100, 100);
canvas.drawRect(rect1, paint_red);
}`
我们首先画了一个绿色矩形框,然后将canvas平移了,接着画了一个红色的矩形框,结果如下
这里我们会发现,平移了canvas之后绿色矩形框没发生变化!,拉近镜头我们仔细看看究竟发生了什么,如何印证canvas每次会产生一个透明图层?
调用canvas.drawRect(rect1, paint_green);时,产生一个Canvas透明图层,由于当时还没有对坐标系平移,所以坐标原点是(0,0);再在系统在Canvas上画好之后,覆盖到屏幕上显示出来,过程如下图(图片来自网络,链接在文后):
然后再第二次调用canvas.drawRect(rect1, paint_red);时,又会重新产生一个全新的Canvas画布,此时由于使用tranlate移动了画布
因而在画图时是以新原点来产生视图的,然后合成到屏幕上,超出部分不显示,最后就是我们看到结果了。
canvas常用方法
下面来清点一下重要的API,绘制颜色就不赘述了
绘制基本形状
drawRoundRecf画圆角矩形
` // 第一种
RectF rectF = new RectF(100,100,400,400);
canvas.drawRoundRect(rectF,30,30,paint_red);
// 第二种 需要api21,一般常用第一种
// canvas.drawRoundRect(100,100,800,400,30,30,paint_red);`
这里是采用第一种方法画出来的,参数30(rx),30(ry)是椭圆的两个半径,用来确定圆角的弧度。
drawOval画椭圆
` // 第一种
RectF rectF = new RectF(100,100,500,400);
canvas.drawOval(rectF,paint_red);
// 第二种
canvas.drawOval(100,100,800,400,paint_red);`
通常也是使用第一种,画椭圆只需要一个矩形即可,椭圆是改矩形的内切
drawArc画圆弧
// 第一种
public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint){}// 第二种
public void drawArc(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean useCenter, @NonNull Paint paint) {}
可以看出这里使用了椭圆的形状,除此之外加上了三个参数
startAngle // 开始角度
sweepAngle // 扫过角度
useCenter // 是否和中心点连成一个封闭的图形
` RectF rectF = new RectF(100, 100, 400, 400);
RectF rectF1 = new RectF(200, 200, 500, 500);
canvas.drawArc(rectF, 0, 40, true, paint_green);
canvas.drawArc(rectF1, 0, 40, false, paint_green);`
画圆弧要清楚,0-40画弧,首先水平那根线是起点,按顺时针40度停止。
drawPath
这个结合path一起使用会非常强大!(path用法也是内涵满满,这里就不展开叙述了)
这里看下canvas中的用法
public void drawPath(@NonNull Path path, @NonNull Paint paint){}
传入路径,和对应的画笔即可
` Path path = new Path();
path.moveTo(50,50);
path.quadTo(30,220,320,450);
canvas.drawPath(path,paint_green);`
这里使用path画了一条贝塞尔曲线
画布裁剪
裁剪涉及到一个Region.Op区域组合的问题
` 假设用region A 去组合region B
public enum Op {
DIFFERENCE(0), //A和B的差集范围,即A - B,只有在此范围内的绘制内容才会被显示;
INTERSECT(1), // 即A和B的交集范围,只有在此范围内的绘制内容才会被显示
UNION(2), //即A和B的并集范围,即两者所包括的范围的绘制内容都会被显示;
XOR(3), //A和B的补集范围,此例中即A除去B以外的范围,只有在此范围内的绘制内容才会被显示;
REVERSE_DIFFERENCE(4), //B和A的差集范围,即B - A,只有在此范围内的绘制内容才会被显示;
REPLACE(5); //不论A和B的集合状况,B的范围将全部进行显示,如果和A有交集,则将覆盖A的交集范围;
} `
clipPath( ),clipRect( ),clipRegion( );通过Path,Rect,Region的不同组合,几乎可以支持任意形状的裁剪区域!
这里演示一个Region.Op.DIFFERENCE,将画笔改为FILL,然后
` canvas.clipRect(10, 10, 110, 110); //第一个
canvas.clipRect(50, 50, 150, 150, Region.Op.DIFFERENCE); //第二个
canvas.drawRect(0, 0, 200, 200, paint_green);`
画布状态
save():把当前状态的状态进行保存,然后放入栈中
restore():把栈顶画布状态取出
画布变换
画布变换主要包括translate(位移)、scale(缩放)、rotate(旋转)、skew(倾斜),画布操作可以帮助我们更加容易的方式制作图形。
【位移translate】
public void translate(float dx, float dy)
基于当前坐标系的移动,并不是屏幕左上角的原点位置
` //构造一个矩形
Rect rect1 = new Rect(0, 0, 200, 100);
canvas.translate(50, 50);
//在平移画布前用绿色画下边框
canvas.drawRect(rect1, paint_green);
//平移画布后,再用红色边框重新画下这个矩形
canvas.translate(50, 50);
canvas.drawRect(rect1, paint_red);`
【缩放scale】
public void scale (float sx, float sy),分别是x,y轴的缩放比例
public final void scale (float sx, float sy, float px, float py),x.y轴的缩放比例,px,py表示缩放中心位置
其中当缩放比例为负数时候会根据缩放中心轴进行翻转
套用网上一个经典的例子(画笔要设置粗一点,不然会有部分显示不全)
` canvas.translate(mWidth/2,mHeight/2);
RectF rectf = new RectF(-300,-300,300,300);
for (int i=0;i<15;i++){
canvas.scale(0.8f,0.8f);
canvas.drawRect(rectf,paint_red);
}`
【旋转 rotate】
public void rotate (float degrees),旋转角度(顺时针)
public final void rotate (float degrees, float px, float py),旋转角度和控制点
这个在画表盘啥的很常用。同样跟位移一样,旋转度数也是可以叠加的。
【错切 skew】
public void skew (float sx, float sy)
float sx:将画布在x方向上倾斜相应的角度,sx倾斜角度的tan值,
float sy:将画布在y轴方向上倾斜相应的角度,sy为倾斜角度的tan值.
`Rect rect1 = new Rect(10,10,200,100);
canvas.drawRect(rect1, paint_green);
canvas.skew(1,0);//X轴倾斜45度,Y轴不变
canvas.drawRect(rect1, paint_red);`
绘制文本
普通水平绘制
drawText
这个比较简单,但是需要注意绘制text绘制精确位置使用FontMetrics,主要包含四个参数
ascent = ascent线的y坐标 - baseline线的y坐标;
descent = descent线的y坐标 - baseline线的y坐标;
top = top线的y坐标 - baseline线的y坐标;
bottom = bottom线的y坐标 - baseline线的y坐标;
指定每个文字位置
void drawPosText (char[] text, int index, int count, float[] pos, Paint paint)
void drawPosText (String text, float[] pos, Paint paint)
参数说明
char[] text:要绘制的文字数组
int index::第一个要绘制的文字的索引
int count:要绘制的文字的个数,用来算最后一个文字的位置,从第一个绘制的文字开始算起
float[] pos:每个字体的位置,同样两两一组,如{x1,y1,x2,y2,x3,y3……}
`float []pos=new float[]{80,100,
100,200,
120,300,
140,400};
canvas.drawPosText("1234", pos, paint);`
··
沿路径绘制
void drawTextOnPath (String text, Path path, float hOffset, float vOffset, Paint paint)
void drawTextOnPath (char[] text, int index, int count, Path path, float hOffset, float vOffset, Paint paint)
参数说明:
float hOffset : 与路径起始点的水平偏移距离
float vOffset : 与路径中心的垂直偏移量
` String string = "测试文字偏移的参数";
Path circlePath = new Path();
circlePath.addCircle(220, 200, 100, Path.Direction.CCW);
canvas.drawPath(circlePath, paint_red);//绘制出路径原形
Path circlePath2 = new Path();
circlePath2.addCircle(550, 200, 100, Path.Direction.CCW);
canvas.drawPath(circlePath2, paint_red);//绘制出路径原形
paint_green.setTextSize(30);
//hoffset、voffset参数值全部设为0,看原始状态是怎样的
canvas.drawTextOnPath(string, circlePath, 0, 0, paint_green);
//第二个路径,改变hoffset、voffset参数值
canvas.drawTextOnPath(string, circlePath2, 80, 30, paint_green);`
常用的基本介绍差不多了还有诸如
drawBitmapMesh:只对绘制的Bitmap作用,使其变形drawVertices:使得画布变形
等等实在撸不动了。
参考文章:
http://blog.csdn.net/harvic880925/article/details/39080931
https://github.com/GcsSloop/AndroidNote/blob/master/CustomView/Advance/[2]Canvas_BasicGraphics.md
http://blog.csdn.net/lonelyroamer/article/details/8349601
http://www.runoob.com/w3cnote/android-tutorial-canvas-api1.html
http://www.cnblogs.com/tianzhijiexian/p/4297664.html
canvas的常见用法的更多相关文章
- Linux中find常见用法
Linux中find常见用法示例 ·find path -option [ -print ] [ -exec -ok command ] {} \; find命令的参数 ...
- php中的curl使用入门教程和常见用法实例
摘要: [目录] php中的curl使用入门教程和常见用法实例 一.curl的优势 二.curl的简单使用步骤 三.错误处理 四.获取curl请求的具体信息 五.使用curl发送post请求 六.文件 ...
- Guava中Predicate的常见用法
Guava中Predicate的常见用法 1. Predicate基本用法 guava提供了许多利用Functions和Predicates来操作Collections的工具,一般在 Iterabl ...
- find常见用法
Linux中find常见用法示例 ·find path -option [ -print ] [ -exec -ok command ] {} \; find命令的参数 ...
- iOS 开发多线程篇—GCD的常见用法
iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...
- iOS开发多线程篇—GCD的常见用法
iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...
- [转]EasyUI——常见用法总结
原文链接: EasyUI——常见用法总结 1. 使用 data-options 来初始化属性. data-options是jQuery Easyui 最近两个版本才加上的一个特殊属性.通过这个属性,我 ...
- NSString常见用法总结
//====================NSStirng 的常见用法==================== -(void)testString { //创建格式化字符串:占位符(由一个%加一个字 ...
- [转]Linux中find常见用法示例
Linux中find常见用法示例[转]·find path -option [ -print ] [ -exec -ok command ] {} \;find命令的参 ...
随机推荐
- Nginx的负载均衡 - 一致性哈希 (Consistent Hash)
Nginx版本:1.9.1 我的博客:http://blog.csdn.net/zhangskd 算法介绍 当后端是缓存服务器时,经常使用一致性哈希算法来进行负载均衡. 使用一致性哈希的好处在于,增减 ...
- 详解EBS接口开发之库存事务处理采购接收--补充
除了可以用 详解EBS接口开发之库存事务处理采购接收的方法还可以用一下方法,不同之处在于带有批次和序列控制的时候实现方式不同 The script will load records into ...
- 后端分布式系列:分布式存储-HDFS Client 设计实现解析
前面对 HDFS NameNode 和 DataNode 的架构设计实现要点做了介绍,本文对 HDFS 最后一个主要构成组件 Client 做进一步解析. 流式读取 HDFS Client 为客户端应 ...
- 安卓banner图片轮播
之前写过一篇关于首页图片广告轮播的demo:http://blog.csdn.net/baiyuliang2013/article/details/45740091,不过图片轮播的指示器(小白点)处操 ...
- Git管理工具对比(GitBash、EGit、SourceTree)
Git管理工具对比(GitBash.EGit.SourceTree) GitBash是采用命令行的方式对版本进行管理,功能最为灵活强大,但是由于需要手动输入希望修改的文件名,所以相对繁琐. EGit是 ...
- iOS中 超简单抽屉效果(MMDrawerController)的实现
ios开发中,展示类应用通常要用到抽屉效果,由于项目需要,本人找到一个demo,缩减掉一些不常用的功能,整理出一个较短的实例. 首先需要给工程添加第三方类库 MMDrawerController: 这 ...
- (六十五)iOS的socket实现(GCDAsyncSocket)
本文介绍使用GCDAsyncSocket来实现iOS端的socket,有关简易服务端的代码已经在上一篇文章中提到,这里不再赘述,将直接介绍如何实现客户端. 首先下载CocoaAsyncSocket框架 ...
- Mysql中limit的用法详解
Mysql中limit的用法详解 在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,为我们提供了limit这样一个功能. SELECT * FROM table LIMIT [offset ...
- 安装Compass时不能访问服务器的问题
今天安装Compass,居然老是提示网络问题,后来根据错误提示,发现带https的域名是访问不了的,是是SSL问题.后来搜了一下,在stackoverflow找到一个人说,将https的去掉就好了.具 ...
- JAVA之旅(十二)——Thread,run和start的特点,线程运行状态,获取线程对象和名称,多线程实例演示,使用Runnable接口
JAVA之旅(十二)--Thread,run和start的特点,线程运行状态,获取线程对象和名称,多线程实例演示,使用Runnable接口 开始挑战一些难度了,线程和I/O方面的操作了,继续坚持 一. ...