Android绘图系列(四)——Canvas操作
来源:互联网 发布:中欧基金 知乎 编辑:程序博客网 时间:2024/06/05 12:51
这个系列主要是介绍下Android自定义View和Android绘图机制,自己能力有限,如果在介绍过程中有什么错误,欢迎指正
一、平移(translate)
translate函数其实实现的相当于平移坐标系,即平移坐标系的原点的位置
void translate(float dx, float dy)
参数说明:
float dx:水平方向平移的距离,正数指向正方向(向右)平移的量,负数为向负方向(向左)平移的量
flaot dy:垂直方向平移的距离,正数指向正方向(向下)平移的量,负数为向负方向(向上)平移的量
请注意,位移是基于当前位置移动,而不是每次基于屏幕左上角的(0,0)点移动
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); paint.setColor(Color.GREEN); paint.setStyle(Paint.Style.FILL); //未平移 Rect rect1 = new Rect(0,0,400,220); canvas.drawRect(rect1, paint); //平移 paint.setColor(Color.RED); canvas.translate(500,300); Rect rect2 = new Rect(0,0,400,220); canvas.drawRect(rect2, paint); }
效果图
注意:两次的坐标原点不一样
二.旋转(rotate)
旋转提供了两种方法:
public void rotate (float degrees) public final void rotate (float degrees, float px, float py)
第一个构造函数直接输入旋转的度数,正数是顺时针旋转,负数指逆时针旋转,它的旋转中心点是原点(0,0)
第二个构造函数除了度数以外,还可以指定旋转的中心点坐标(px,py)注意:默认的旋转中心依旧是坐标原点
- 不指定旋转中心
//不指定旋转中心 canvas.rotate(30); paint.setColor(Color.RED); Rect rect2 = new Rect(0,0,400,220); canvas.drawRect(rect2, paint);
效果图
-指定旋转中心
//指定旋转中心 canvas.rotate(180,200,200); paint.setColor(Color.RED); Rect rect2 = new Rect(0,0,400,220); canvas.drawRect(rect2, paint);
注意:旋转是可叠加的
canvas.rotate(100); canvas.rotate(50);
调用两次旋转,则实际的旋转角度为100+50=150度。
三.缩放(scale)
缩放提供了两个方法,如下:
public void scale (float sx, float sy) public final void scale (float sx, float sy, float px, float py)
这两个方法中前两个参数是相同的分别为x轴和y轴的缩放比例。而第二种方法比前一种多了两个参数,用来控制缩放中心位置的。
缩放比例(sx,sy)取值范围详解:
注意:缩放的中心默认为坐标原点,而缩放中心轴就是坐标轴
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint=new Paint(); paint.setColor(Color.GREEN); paint.setStyle(Paint.Style.FILL); RectF rectF=new RectF(0,0,400,400); canvas.drawRect(rectF,paint); //未控制缩放点 canvas.scale(0.5f,0.5f); paint.setColor(Color.RED); canvas.drawRect(rectF,paint); }
接下来我们使用第二种方法让缩放中心位置稍微改变一下,如下:
// 将坐标系原点移动到画布正中心 //控制缩放点 //缩放中心向右偏移了200个单位 canvas.scale(0.5f,0.5f,200,0); paint.setColor(Color.RED); canvas.drawRect(rectF,paint);
前面两个示例缩放的数值都是正数,按照表格中的说明,当缩放比例为负数的时候会根据缩放中心轴进行翻转,下面我们就来实验一下:
//指定负数缩放比例 canvas.scale(-0.5f,-0.5f);// paint.setColor(Color.RED); canvas.drawRect(rectF,paint);
由于本次未对缩放中心进行偏移,所有默认的缩放中心就是坐标原点,中心轴就是x轴和y轴。
本次缩放可以看做是先根据缩放中心(坐标原点)缩放到原来的0.5倍,然后分别按照x轴和y轴进行翻转。
//指定负数缩放比例 canvas.scale(-0.5f,-0.5f,200,0);// paint.setColor(Color.RED); canvas.drawRect(rectF,paint);
PS:和位移(translate)一样,缩放也是可以叠加的。
canvas.scale(0.5f,0.5f); canvas.scale(0.5f,0.1f);
调用两次缩放则 x轴实际缩放为0.5x0.5=0.25 y轴实际缩放为0.5x0.1=0.05
注意:下面的例子截取自网络
下面我们利用这一特性制作一个有趣的图形。
// 将坐标系原点移动到画布正中心 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); }
四.斜切Skew
void skew (float sx, float sy)
参数说明:
float sx:将画布在x方向上倾斜相应的角度,sx倾斜角度的tan值,
float sy:将画布在y轴方向上倾斜相应的角度,sy为倾斜角度的tan值,
注意,这里全是倾斜角度的tan值哦,比如我们打算在X轴方向上倾斜60度,tan60=根号3,小数对应1.732
变换后:
X = x + sx * yY = sy * x + y
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //skew 扭曲 Paint paint=new Paint(); paint.setColor(Color.GREEN); paint.setStyle(Paint.Style.FILL); Rect rect = new Rect(0,0,200,200); canvas.drawRect(rect, paint); canvas.skew(1,0);//X轴倾斜45度,Y轴不变 paint.setColor(Color.RED); canvas.drawRect(rect, paint); }
五.裁剪Clip
裁剪画布是利用Clip系列函数,通过与Rect、Path、Region取交、并、差等集合运算来获得最新的画布形状。除了调用Save、Restore函数以外,这个操作是不可逆的,一但Canvas画布被裁剪,就不能再被恢复!
Clip系列函数如下:
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)
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.RED); canvas.clipRect(new Rect(100, 100, 200, 200)); canvas.drawColor(Color.GREEN); }
六.保存(save)和恢复(restore)
画布的操作是不可逆的,而且很多画布操作会影响后续的步骤,所以会对画布的一些状态进行保存和回滚。
说一个状态栈的概念,这个栈可以存储画布状态和图层状态。
先进行三次save
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.RED); //保存的画布大小为全屏幕大小 canvas.save(); canvas.clipRect(new Rect(100,100,800,800)); canvas.drawColor(Color.GREEN); canvas.save(); canvas.clipRect(new Rect(100,100,600,600)); canvas.drawColor(Color.YELLOW); canvas.save(); }
进行一次restore
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.RED); //保存的画布大小为全屏幕大小 canvas.save(); canvas.clipRect(new Rect(100,100,800,800)); canvas.drawColor(Color.GREEN); canvas.save(); canvas.clipRect(new Rect(100,100,600,600)); canvas.drawColor(Color.YELLOW); canvas.save(); canvas.clipRect(new Rect(100,100, 400, 400)); canvas.drawColor(Color.WHITE); canvas.restore(); canvas.drawColor(Color.BLUE); }
进行三次restore
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.RED); //保存的画布大小为全屏幕大小 canvas.save(); canvas.clipRect(new Rect(100,100,800,800)); canvas.drawColor(Color.GREEN); canvas.save(); canvas.clipRect(new Rect(100,100,600,600)); canvas.drawColor(Color.YELLOW); canvas.save(); canvas.clipRect(new Rect(100,100, 400, 400)); canvas.drawColor(Color.WHITE); canvas.restore(); canvas.restore(); canvas.restore(); canvas.drawColor(Color.BLUE); }
OK啦,这篇就到了啦。
Github地址
参考:
http://www.gcssloop.com/customview/Canvas_Convert
http://blog.csdn.net/harvic880925/article/details/39080931
- Android绘图系列(四)——Canvas操作
- Android绘图初步—Canvas
- 自定义控件之绘图篇(四) —— Canvas变换与操作
- HTML5中的Canvas绘图操作(四)
- canvas绘图基础(四)
- Android基础知识(9)—Android绘图基础Canvas、Paint
- android之绘图——Canvas,bitmap,Paint的理解
- 浅谈android——Canvas绘图基础详解
- 【canvas】Android Canvas绘图详解
- HTML5学习(四)---Canvas绘图
- android 绘图 Canvas
- Android Canvas绘图
- Canvas绘图android机器人
- Android--使用Canvas绘图
- Android绘图Canvas、Paint
- Android Canvas绘图详解
- android 高级Canvas绘图
- Android Canvas绘图详解
- (32)Java学习笔记——集合框架 / Collection 接口 / Iterator 迭代器
- Android客户端连接服务器端,向服务器端发送请求HttpURLConnection
- Java基础语法简介
- 快速排序
- Java 三大特质之多态
- Android绘图系列(四)——Canvas操作
- 报org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver: method <init>()
- Handler一定要在主线程实例化吗?new Handler()和new Handler(Looper.getMainLooper())的区别
- dbus-python服务实现及introspection功能
- 静态代理动态代理以及aop
- numpy数组创建初步
- 新的开始从今天开始
- CNN卷积神经网络新想法
- 内容提供者ContentProvider