Android绘图技巧
来源:互联网 发布:照片大小调整软件 编辑:程序博客网 时间:2024/06/09 23:12
再学完Android的基本绘图技巧之后,下面来讲解一些再Android中常用的绘图技巧。通过这些技巧学习来简化优化Android的绘图操作。
1.Canvas
Canvas作为绘制图形的直接对象,提供了以下几个非常有用的方法。
- Canvas.save()
- Canvas.restore()
- Canvas.translate()
- Canvas.rotate()
首先,来看Canvas.save()和Canvas.restore()这两个方法。
再讲解这两个方法之前,首先了解下Android绘图的坐标体系。在Android中,默认的坐标零点位于屏幕左上角,向下为Y轴正方向,向右为X轴正方向。Android中的绘图,一般情况下困难之处在与对坐标的计算上。因此绘图者不应该把自己看作时一个完成任务的人,而应该把自己当成一个设计者,你是在设计这些图形而不是机械地绘制。
Canvas.save()这个方法,从字面上可以理解为保存画布。它的作用就是将之前的所有已绘制图像保存起来,让后续的操作就好像在一个新的图层上操作一样,这一点与Photoshop中的图层理解基本一致。
而Canvas.restore()这个方法则可以理解为Photoshop中的合并图层操作。它的作用是将我们在save()之后的所有图像与save()之前的图像进行合并。
那么translate()方法与rotate()方法呢?虽然从字面上看,可以将他们理解为是画布平移、画布翻转,但是把他理解为坐标系平移与翻转则会更加形象。前面说了,默认绘图坐标零点位于屏幕左上角,那么在调用translate(x,y)方法之后,则将原点(0,0)移动到了(x,y)。之后的所有绘图操作都将以(x,y)为原点执行。同理,rotate()方法也是一样,它将坐标系旋转了一定的角度。大家也许会想,这样的操作有什么用呢?的确,没有这两个方法,同样可以绘图,只要计算好坐标,没有什么画不出来的。所以说,这些方法是Android用来帮助我们简化绘图而创建的。这么说可能比较抽象,来看一个具体实例,大家技能明白其中的奥妙了。例如,需要创建一个下图的仪表盘。
先来分析下要画的这个图形。要完成这样一个图像,可以将它分解成以下几个元素。
- 仪表盘:外面的大盘。
- 刻度线:包含四个长的刻度线和其他短的刻度线
- 刻度值:包含长刻度线对应的大的刻度值的其他小的刻度值
- 指针:中间的指针,一粗一细两根指针
相信如果在现实中叫你去画这样一个仪表盘,你应该也会这样去画。实际上,Android中的绘图与现实中的绘图十分相似,与Photoshop中的绘图则更是相似。所以,当你要绘制一个复杂的图形的时候,不妨想想自己在显示中该如何去左,顺着这个思路也许就能找到解决问题的方法了。
在这个实例中,第一步画圆盘,已经可以非常轻松的实现了,也就是调用canvas.drawCircle()方法绘制一个圆就可以了。关键在于确定圆心和半径。这里为了简单演示,我们把圆心定在屏幕中心而半径就为屏幕宽度的一般,代码如下所示。
Paint paint = new Paint(); paint.setStrokeWidth(5); paint.setStyle(Paint.Style.STROKE); paint.setAntiAlias(true); canvas.drawCircle(mScreenWidth/2, mScreenHeight/2, mScreenWidth/2, paint);
下面是画刻度线,这个也很简单,一条线而已,只需要确定线端两个端点的坐标就可以了。第一根线还比较简单,坐标非常容易确定。可后面的问题来了,那些斜着的线的端点坐标无法通过简单的左边加减来获得,必须要通过角度来计算三角函数菜可以获得具体的坐标。这时你就会发现,简简单单的一个仪表盘,你甚至要把三角函数用个遍才能算出这些点的坐标。不仅仅运算量大,而且非常容易出错,这当然是非常难以接受的。所以我们来看看Android是如何简化这些运算的。
从图中可以看出,我们之所以觉得不好画,就是因为那个“可恶”的角度。那么如果将画布以圆心为原点旋转到需要的角度呢?每当画好一根线,就旋转相应的角度。虽然下一次画线的时候,依然是第一根线的坐标,但是实际上当我们把画布重新还原到旋转位置时,所以的刻度就已经全部画好了。通过旋转画布------实际上时旋转了画图的坐标体系这就避免了进行复杂的三角函数运算。通过这样一种相对论式的变换,简洁简化了绘图,这是再去绘制这些刻度线,就只需要区别整点与非整点刻度线就可以了。代码如下所示。
//画刻度和数值 Paint paintDegree = new Paint(); paintCircle.setStrokeWidth(3); for (int i=0; i<24; i++){ //区分整点和非整点 if(i%6 == 0) { paintDegree.setStrokeWidth(5); paintDegree.setTextSize(30); canvas.drawLine(mScreenWidth/2, mScreenHeight/2 -mScreenWidth/2, mScreenWidth/2,mScreenHeight/2 -mScreenWidth/2+60,paintDegree); String degree = String.valueOf(i); canvas.drawText(degree,mScreenWidth/2 - paintDegree.measureText(degree)/2, mScreenHeight/2-mScreenWidth/2+90,paintDegree); } else { paintDegree.setStrokeWidth(3); paintDegree.setTextSize(15); canvas.drawLine(mScreenWidth/2, mScreenHeight/2 -mScreenWidth/2, mScreenWidth/2,mScreenHeight/2 -mScreenWidth/2+30,paintDegree); String degree = String.valueOf(i); canvas.drawText(degree,mScreenWidth/2 - paintDegree.measureText(degree)/2, mScreenHeight/2-mScreenWidth/2+60,paintDegree); } canvas.rotate(15,mScreenWidth/2,mScreenHeight/2);
最后来画那两根指针。同样只是简单的画两个线段而已,只要计算好起始点的坐标就可以了。起点自然时圆心,终点就是在圆心的坐标基础上的加减。但前面介绍了rotate()方法,那么自然也不能亏待了translate()方法。所以,我们通过画这两根指针来看看如何使用translate()方法。在前文中,我们讲解了translate()方法用来平移坐标原点,将其从(0,0)的位置上移动到新的坐标。这个新的坐标自然是能够帮助我们简化绘制图的坐标。那么通过translate()将原点移动到圆心,这样再画线段的时候就可以理解为从原点开始画一条线段了。使用translate()方式,代码如下所示。
//画指针 Paint paintHour = new Paint(); paintHour.setStrokeWidth(20); Paint paintMinute = new Paint(); paintMinute.setStrokeWidth(10); canvas.save(); canvas.translate(mScreenWidth/2,mScreenHeight/2); canvas.drawLine(0,0,100,100,paintHour); canvas.drawLine(0,0,100,200,paintMinute); canvas.restore();
最后的绘图的效果就和上图一样的了。
2.Layer图层
Android中的绘图API,很大成度上都来自于现实生活中的绘图,特别是借鉴了很多Photoshop中的概念,比如图层的概念。那么什么是图层呢?相信用过Photoshop的朋友一定会非常情况,一张复杂的画可以由很多个图层叠加起来,形成一个复杂的图像。再Android中,使用saveLayer()方法来创建一个图层,图层同样是基于栈结构进行管理的。如下图所示。
Android通过调用saveLayer()方法、saveLayerAlpha()方法将一个图层入展,使用restore()方法、restoreToCount()方法将一个图层出栈。入栈的时候,后面所有的操作都发生再这个图层上,而出栈的时候,则会把图形绘制到上层Canvas上。下面我们就仿照Api Demos里面的一个实例来看看如何使用Layer,代码如下所示。
@Override protected void onDraw(Canvas canvas) { Paint paint = new Paint(); canvas.drawColor(Color.WHITE); paint.setColor(Color.BLUE); canvas.drawCircle(150,150,100,paint); canvas.saveLayerAlpha(0,0,400,400,127,Canvas.ALL_SAVE_FLAG); paint.setColor(Color.RED); canvas.drawCircle(200,200,100,paint); canvas.restore(); }
在onDraw方法中绘制两个相交的圆,当然这两个圆位于两个图层上。
接下来后面的图层透明度设置为0~255不同的数值,看看不同的透明度的值,效果有何不同。
当透明度为127是,即半透明。当透明度为255时,即完全不透明。当透明度为0时,即完全透明。效果图分别如下所示。