Android 绘图技巧

在前面我们说了Android的基本绘图技巧,下面我们聊聊Android中常用的一些绘图技巧。通过这些技巧学习来简化、优化Android的绘图操作。

一、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用来帮助我们简化绘图而创建的。这么说可能比较抽象,来看一个具体的实例,大家就能明白其中的奥妙了。例如,需要创建一和如图(1)所示的仪表盘。

 

                                                    

                                                                                  (1)仪表盘

先来分析一下要画的这个图形。要完成这样一个图形,可以将它分解成以下几个元素。

1、仪表盘——外面的大圆盘

2、刻度线——包含四个长的刻度线和其他短的刻度线

3、刻度值——包含长刻度线对应的大的刻度值和其他小的刻度值

4、指针——中间的指针,一粗一细两根指针

相信如果在现实中叫你去画这样一个仪表盘,你应该也会这样去画。实际上,Android中的绘图与实现中的绘图十分相似,与Photoshop中的绘图则更是相似。所以,当你要绘制一个复杂的图形的时候,不妨想想自己在显示中该如何去做,顺着这个思路也许就能找到解决问题的方法了。

在这个实例中,第一步画圆盘,已经可以轻松的实现了,也就是调用xanvas.drawCircle(方法绘制一个圆就可以了。关键在于确定圆心和半径。这里为了简单演示,我们把圆心定在屏幕中心而半径就为屏幕的一半,代码如下所示。

 

        Paint painCircle = new Paint();
        painCircle.setColor(Color.RED);
        painCircle.setStyle(Paint.Style.STROKE);
        painCircle.setAntiAlias(true);
        painCircle.setStrokeWidth(5);
        canvas.drawCircle(mWidth/2,mHeight/2,mWidth/2,painCircle);

下面画刻度线,这个也很简单,一条线而已,只需要确定线段两个端点的坐标就可以了。第一根线还还比较简单,坐标非常容易确定。可后面的问题就来了,那些斜着的线的端点坐标无法通过简单的坐标加减来获得,必须通过角度来计算三角偶数用个遍才能算出这些点的坐标。不仅运输量大,而且非常容易出错,这当然也是非常满意接受的。所以我们来看看Android是如何简化这些运算的。

从图一中可以看出,我们之所以感觉不好画,就是因为那恶心的角度。那么如果将画布已圆心为原点为原点旋转到需要的角度呢?当灭画好一根线,就旋转相应的角度。虽然下一次画线的时候,依然是第一根线的坐标,但是实际上当我们把画布重新还原当选择前的位置时,所有的刻度就已经全部画好了。通过旋转画布——实际上是旋转了画图的坐标系,这就避免了进行复杂的三角偶数运算。通过这的相对论的变换,间接简化了绘图,这样在去绘制这些刻度线,就只需要区别整点与非整点刻度线就可以了,代码如下所示。

        Paint paintDegree = new Paint();
        paintDegree.setColor(Color.RED);
        painCircle.setStrokeWidth(3);
        for (int i =0;i<24;i++){
            if (i==0||i==6||i==12||i==18){
                paintDegree.setStrokeWidth(5);
                paintDegree.setTextSize(30);
                canvas.drawLine(mWidth/2,mHeight/2-mWidth/2,mWidth/2,mHeight/2-mWidth/2+60,paintDegree);
                String degree = String.valueOf(i);
                canvas.drawText(degree,mWidth/2-paintDegree.measureText(degree)/2,mHeight/2-mWidth/2+90,paintDegree);

            }else {
                paintDegree.setStrokeWidth(3);
                paintDegree.setTextSize(15);
                canvas.drawLine(mWidth/2,mHeight/2-mWidth/2,mWidth/2,mHeight/2-mWidth/2+30,paintDegree);
                String degree = String.valueOf(i);
                canvas.drawText(degree,mWidth/2-paintDegree.measureText(degree)/2,mHeight/2-mWidth/2+60,paintDegree);
            }
            canvas.rotate(15,mWidth/2,mHeight/2);
        }

最后来画那两根指针。同样只是简单地画两个线段而已,只要算好起始点的坐标就可以了。起点自然是圆心,终点就是在圆心的坐标基础上的加减。但前面介绍了rotate()方法,那么自然也不能亏待了translate()方法。所以,我们通过画这两根指针来看看如何使用translat()方法。在前文中,我们讲了translate()方法用来平移坐标原点,将其从(0,0)的位置上移动到新的坐标。这个新的坐标自然是能够帮助我们简化绘图的坐标。那么通过translate()方法将原点移动到原点,这样再画线段的时候就可以理解为从原点开始画一条线段了。使用translate()方法,代码如下所示。

        Paint paintHour = new Paint();
        paintHour.setColor(Color.RED);
        paintHour.setStrokeWidth(20);
        Paint paintMinute = new Paint();
        paintMinute.setColor(Color.RED);
        paintMinute.setStrokeWidth(10);
        canvas.save();
        canvas.translate(mWidth/2,mHeight/2);
        canvas.drawLine(0,0,100,100,paintHour);
        canvas.drawLine(0,0,100,200,paintMinute);
        canvas.restore();

最后绘图的效果就和图(1)所示的一样了。

二、Layer图层

Andriud中的绘图API,很大程度上都来自与现实生活中的绘图,特别是借鉴了很多Photoshop中的概念,比如图层概念。那么什么是图层呢?相信用过Photoshop的朋友一定会非常清楚,一张复杂的图可以很多个图层叠加起来,形成一个复杂的图像。在Android中,使用saveLayer()方法来创建一个图层,图层同样是基于栈的结构进行管理的,如图(2)所示。

 

                                                 

                                                                             (2)图层的栈管理结构

Android通过调用saveLayer()方法、savaLayerAlpha()方法将一个图层入栈,使用restore()方法、restoreToCount()方法将一个图层出栈。入栈的时候,后面所有的操作都发生在这个图层上,而出栈的时候,则会把图像绘制到上层。下面我么就仿照API Demos里面的一个示例来看看该如何使用Layer,代码如下所示。

        Paint mPaint = new Paint();
        canvas.drawColor(Color.WHITE);
        mPaint.setColor(Color.BLUE);
        canvas.drawCircle(150,150,100,mPaint);

        canvas.saveLayerAlpha(0,0,400,400,127,0);
        mPaint.setColor(Color.RED);
        canvas.drawCircle(200,200,100,mPaint);
        canvas.restore();

在onDraw方法中绘制两个相交的圆,当然这个两个圆位于两个图层上。

接下来,将后面的图层透明度设置为0~255不同的数组值,看看不同的透明值效果有何不同。

当透明度为127是,即半透明,效果如图(3)所示。

当透明度为255时,即完全不透明,效果如图(4)所示。

当透明度为0时,即完全透明,效果如图(5)所示。

                               

                                   (3)                                                  (4)                                                     (5)

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值