Canvas的变换
来源:互联网 发布:windows api大全 编辑:程序博客网 时间:2024/06/08 04:31
Canvas变换
之前看了Canvas的一些基本用法,由于时间问题有些东西没有总结出来,今天继续Canvas变换相关笔记的总结!
一、变换主要有四种,name我们就从下面的几个方面入手
- Canvas的区域、以及坐标原点
- Canvas的平移(translate)
- Canvas的旋转(rotate)
- Canvas的缩放(scale)
- Canvas的错切(skew)
二、Canvas概述
首先我们需要建立一个意识,就是Canvas是无边界的,不要觉得我们给View设置了大小就认为Canvas的默认大小也跟view的大小一样,其实很好理解,当我们在Canvas上进行绘制的时候(比如说绘制一个点),我们的坐标时候可以填写负值得,这时如果我们没有对Canvas做过任何转换操作的话我们是看不到那个点的,但是,点是存在的,只是在可见区域外面而已。其次就是,Canvas默认的坐标原点是跟View的坐标原点是重合的。看下图:
三、变换的几个关键方法
1、translate(),这个方法只有两个参数,一个是坐标系原点的x坐标,一个是坐标系原点的y坐标,当调用这个方法后,后面的所有canvas的操作都以最新的坐标系为标准,下面我们在默认状态下,还有将坐标系到View的中心状态下画圆看看会有什么不同的效果。
@RequiresApi(api = Build.VERSION_CODES.KITKAT)@Overrideprotected void onDraw(Canvas canvas) { super.onDraw(canvas); //设置画布背景颜色 canvas.drawColor(Color.YELLOW); //创建画笔 Paint paint = new Paint(); paint.setColor(Color.RED); paint.setStyle(Paint.Style.FILL); paint.setStrokeWidth(10.0f); paint.setAntiAlias(true); /** * 在默认坐标系绘制矩形 */ canvas.drawRect(0,0,100,100,paint); //将坐标系的原点移动到控件的中心 canvas.translate(getMeasuredWidth() / 2, getMeasuredHeight() / 2); /** * 在新坐标系绘制矩形 */ canvas.drawRect(0,0,100,100,paint);}
2、rotate(),旋转,这个方法应该是写自定义控件用的比较多的一个,特别是在绘制多样化的圆时,就比如我们要绘制一个圆形时钟,那么上面的刻度都是平均分配的,都是每1度就一个刻度,这个时候如果我们每绘制一个刻度都去计算一次刻度的坐标,那就相当麻烦了,相比之我们每绘制一个刻度就按照一定的比例旋转一下画布,这样就省事多了!那么下面就简单的画一个时钟的刻度瞅瞅!
@RequiresApi(api = Build.VERSION_CODES.KITKAT)@Overrideprotected void onDraw(Canvas canvas) { super.onDraw(canvas); //设置画布背景颜色 canvas.drawColor(Color.YELLOW); /** * 要注意的是,这些笔的初始化这里只是为了减少篇幅,所以在onDraw中初始化,正确的做法应该是在控件的构造方法中 */ //绘制时钟外圈跟(3、6、9、12)这几个整点的刻度的笔 Paint pc = new Paint(); pc.setColor(Color.RED); pc.setStyle(Paint.Style.STROKE); pc.setStrokeWidth(5.0f); pc.setAntiAlias(true); //绘制小时刻度 Paint ph = new Paint(); ph.setColor(Color.RED); ph.setStyle(Paint.Style.STROKE); ph.setStrokeWidth(3.0f); ph.setAntiAlias(true); //绘制分钟刻度的笔 Paint pm = new Paint(); pm.setColor(Color.RED); pm.setStyle(Paint.Style.STROKE); pm.setStrokeWidth(1.0f); pm.setAntiAlias(true); //创建画文字专用画笔 TextPaint pt = new TextPaint(); pt.setColor(Color.RED); pt.setStyle(Paint.Style.FILL); pt.setAntiAlias(true); pt.setTextSize(24); //获取view宽高 float width = getMeasuredWidth(); float height = getMeasuredHeight(); //移动坐标系到view中心 canvas.translate(width / 2 + 0.5f, height / 2 + 0.5f); //以较小的为标准 float radius = width > height ? height / 2 - 50.0f + 0.5f : width / 2 - 50.0f + 0.5f; //画外圈 canvas.drawCircle(0, 0, radius, pc); //中心点 canvas.drawCircle(0, 0, 20, pc); //时钟一圈有60分,所以canvas需要旋转60次 int m = 60; //记录当前处于哪个刻度 int count = 0; //每个小时的文字 int time = 0; for (int i = 0; i < m; i++) { //绘制12、3、6、9四个刻度 if (count % 15 == 0) { canvas.drawLine(0, -radius + 2.5f, 0, -radius + 22.5f, pc); if (count == 0) { //绘制文字这里正常来说需要获得文字区域的宽度,才能确定文字的会之后坐标的(我偷懒就估摸着写了一些值进去) canvas.drawText("12", -12, -radius + 50.0f, pt); } else { canvas.drawText(String.valueOf(time), -12, -radius + 50.0f, pt); } canvas.rotate(6); count += 1; time += 1; continue; } //绘制整点刻度 if (count % 5 == 0) { canvas.drawLine(0, -radius + 2.5f, 0, -radius + 12.5f, ph); canvas.drawText(String.valueOf(time), -12, -radius + 50.0f, pt); canvas.rotate(6); count += 1; time += 1; continue; } //绘制分钟刻度 canvas.drawLine(0, -radius + 2.5f, 0, -radius + 6.5f, pm); //旋转画布(每次旋转6度),注意默认旋转的方向是逆时针的,默认旋转中心是坐标系原点,rotate()还有一个重载方法,可以根据参数指定旋转中心 canvas.rotate(6); count++; }}
最终效果图如下,至于几根针就懒的弄上去了,无非是坐标的计算问题,难度不大,就是繁琐一些而已:
3、scale(),缩放的方法是我觉得最不好理解的,因为当我们缩放之前画一个区域A,然后进行缩放再画一个区域B,起初我还以为A也会被缩放,因为A是被绘制在Canvas上的,既然我们对canvas进行了缩放,那么应该所有的元素都会被影响,可是代码写完后发现受影响的只有B,而A还是原来的鬼样子,看代码!
@RequiresApi(api = Build.VERSION_CODES.KITKAT)@Overrideprotected void onDraw(Canvas canvas) { super.onDraw(canvas); //设置画布背景颜色 canvas.drawColor(Color.YELLOW); Paint pc = new Paint(); pc.setColor(Color.RED); pc.setStyle(Paint.Style.FILL); pc.setAntiAlias(true); //先画一个红色小块 canvas.drawRect(50,50,200,200, pc); /** * 参数1、x轴方向缩放(0-1之间为缩小,大于1为放大) * 参数2、y轴方向缩放(0-1之间为缩小,大于1为放大) * 参数3、缩放中心点的x坐标 * 参数4、缩放中心点的y坐标 */ canvas.scale(0.5f,0.5f,0,0); pc.setColor(Color.BLUE); //进行缩放后再画个蓝色小块 canvas.drawRect(50,50,200,200,pc);}
面代码比较简单,就不多说了,记住几个参数的意义就可以,为了更好的理解缩放中心点对整个缩放效果的影响,我把上面的缩放中心的改成了50,50,看看两张图的效果对比下:
/*** 参数1、x轴方向缩放(0-1之间为缩小,大于1为放大)* 参数2、y轴方向缩放(0-1之间为缩小,大于1为放大)* 参数3、缩放中心点的x坐标* 参数4、缩放中心点的y坐标*/canvas.scale(0.5f,0.5f,50,50);
4、接下来看下错切,说实在话,要做出很炫的效果,特别是图片的效果,这个东西经常用到,而且在矩阵部分也用得非常多,但是有点难理解,那么我们先写个例子出来看看效果怎么样,再慢慢分析吧!
mPaint.setColor(Color.RED);mPaint.setStyle(Paint.Style.FILL);mPaint.setAntiAlias(true);RectF rectF = new RectF(0, 0, 300, 300);canvas.drawRect(rectF,mPaint);/*** 参数1、水平方向的错切因子* 参数2、垂直方向的错切因子*/canvas.skew(1f,0);mPaint.setColor(Color.BLUE);canvas.drawRect(rectF,mPaint);
下面第一张图是对x方向进行错切,第二张图时候对y方向进行错切
由图中我们可以看出,由于我们只对x轴进行的错切,所以图形是在x轴方向上变化了,在y轴方向上还是在原来的范围内的,我之前看了一些网上的资料,看到了一个公式:
x轴错切:原始坐标(x,y)=》错切后坐标(x+ay,y)
y轴错切:原始坐标(x,y)=》错切后坐标(x,y+ax)
上面的公式,适用于所有的点,而那个a就是我们在代码中设置的错切因子,也就是canvas(a,a),那么现在的主要问题就是,这个a时候怎么来的?下面我们再看一张图:
看看这张图,当我们的的错切因子为1的时候,蓝色框框的一条边刚好跟正方形的对角线重合,也就是说角a=45°,那么当错切因子不断变大的时候,角a也是不断增大的,这跟高中学的三角函数的正切老像了,其实就是了,也就是tana,可以多填些角度进去进行验证!既然知道错切因子就是偏移角度的正切值,那么以后想要得到对应偏移量的错切因子也是so easy了,y方向也是同样道理的!!
阅读全文
0 0
- Canvas的图形变换
- canvas的各种变换
- Canvas的变换
- html5的canvas坐标变换
- 浅谈canvas的matrix变换
- canvas变换
- canvas变换
- canvas变换
- Canvas---Canvas变换与操作
- Canvas之变换初步
- canvas变换与操作
- canvas画布变换画六芒星
- canvas中的变换
- Html5 Canvas 变换矩阵与坐标变形之间的关系
- Html5 Canvas 变换矩阵与坐标变形之间的关系
- Html5 Canvas 变换矩阵与坐标变形之间的关系
- 自定义控件(11)---Canvas的平移、旋转、缩放、错切、Matrix直接变换Canvas
- 07、canvas标签之canvas变换
- ubuntu14.04+GTX1060 重新安装显卡驱动
- wx.readBLECharacteristicValue返回参数的问题
- apk反编译
- 最长公共子序列+元素打印
- jQuery源码分析一
- Canvas的变换
- unity的2D中物体在Scene窗口中可以看到,但在Game窗口中看不到
- PIL IOError: cannot open resource处理
- javascript 数组方法
- iReport 报表展示报错:Error filling print... Error evaluating expression
- GPU渲染流程学习_02_阴影
- 背包问题
- POI 动态生成ECXEL
- JQuery 自定义事件的使用