Android绘图机制与处理技巧(一)——Android绘图技巧

Canvas

Canvas作为绘制图形的直接对象,提供了以下几个非常有用的方法。

  • canvas.save()
  • canvas.restore()
  • canvas.rotate()
  • canvas.translate()

canvas.save()这个方法,从字面上可以理解为保存画布。它的作用就是将之前的所有已绘制图像保存起来,让后续的操作就好象在一个新的图层上操作一样,这一点与Photoshop中的图层理解基本一致。

canvas.restore()这个方法,则可以理解为Photoshop中的合并图层操作。它的作用是将我们在save()之后绘制的所有图像与save()之前的图像进行合并。

canvas.rotate()与canvas.translate()方法从字面上看,可以将它们理解为画布平移、画布翻转,但是把它理解为坐标系的平移与翻转则会更加形象。默认绘图坐标零点位于屏幕左上角,在调用translate(x, y)方法之后,则将原点(0, 0)移动到了(x, y)。之后的所有绘图操作都将以(x, y)为原点执行。同理,rotate()方法就是将坐标系旋转了一定的角度。没有这两个方法,同样可以绘图,只要计算好坐标,没有什么画布出来的。但是Android提供这些方法是用来帮助我们简化绘图的。例如,创建如下的一个仪表盘:

这里写图片描述

要完成这样一个图形,可以将它分解成以下几个元素:

  1. 仪表盘——外面的大圆
  2. 刻度线——包含四个长的刻度线和其它短的刻度线
  3. 刻度值——包含长刻度线对应的大的刻度值和其他小的刻度值
  4. 指针——中间的指针,一粗一细两根指针
绘制圆盘

调用 canvas.drawCircle()方法绘制一个圆即可,关键在于确定圆心和半径。这里,我们把圆心定在屏幕中心而半径为屏幕宽的一半。

        // 获取宽高参数
        mHeight = getMeasuredHeight();
        mWidth = getMeasuredWidth();

        // 画外圆
        Paint paintCircle = new Paint();
        paintCircle.setAntiAlias(true);
        paintCircle.setStyle(Paint.Style.STROKE);
        paintCircle.setStrokeWidth(5);
        canvas.drawCircle( mWidth / 2, mHeight /2, mWidth /2, paintCircle);
绘制刻度线与刻度值

绘制第一个线比较简单,坐标非常容易确定。可那些斜着的线的端点坐标无法通过简单的坐标加减来获得,必须通过角度来计算三角函数才可以获得具体的坐标。这样不仅运算量大,而且非常容易出错。

如果我们将画布以圆心为原点旋转到需要的角度,每当画好一根线,就旋转相应的角度。虽然下一次画线的时候,依然是第一根线的坐标,但是实际上当我们把画布重新还原到旋转前的位置时,所有的刻度线就已经全部画好了。通过旋转画布——实际上是旋转了画图的坐标系,这就避免了进行复杂的三角函数运算。通过这样一种相对论式的变换,间接简化了绘图,这时再去绘制这些刻度线,就只需要区分整点与非整点刻度线就可以了。

        // 画刻度与刻度线
        Paint paintDegree = new Paint();
        for (int i = 0; i < 24; i++) {
            // 区分整点与非整点
            if(i == 0 || i == 6 || i == 12 || i == 24){
                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);
        }
绘制指针

最后绘制那两根指针,同样只是简单地画两个线段而已,只要算好起始点的坐标就可以了。起点自然是圆心,终点就是在圆心的坐标基础上的加减。通过translate()方法将原点移动到圆心,这样再画线段的时候就可以理解为从原点开始画一条线段了。

        // 画圆心
        Paint paintPoint = new Paint();
        paintPoint.setStrokeWidth(30);
        canvas.drawPoint(mWidth / 2, mHeight / 2, paintPoint);

        // 画指针
        Paint paintHour = new Paint();
        paintHour.setStrokeWidth(20);
        Paint paintMinute = new Paint();
        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();

Layer

在Photoshop中,一张复杂的画可以由很多个图层叠加起来,形成一个复杂的图像。在Android中,使用saveLayer()方法来创建一个图层,图层同样是基于栈的结构进行管理的。

Android通过调用saveLayer()方法、saveLayerAlpha()方法将一个图层入栈,使用restore()方法、restoreToCount()方法将一个图层出栈。入栈的时候,后面所有的操作都发生在这个图层上,而出栈的时候,则会把图像绘制到上层Canvas上。

    private static final int LAYER_FLAGS =
            Canvas.MATRIX_SAVE_FLAG |
                    Canvas.CLIP_SAVE_FLAG |
                    Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
                    Canvas.FULL_COLOR_LAYER_SAVE_FLAG |
                    Canvas.CLIP_TO_LAYER_SAVE_FLAG;

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.WHITE);
        mPaint.setColor(Color.BLUE);
        canvas.drawCircle(150, 150, 100, mPaint);

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

在onDraw()方法中绘制两个相交的圆,并且这两个圆位于两个图层上。接下来将后面的图层透明度设置为0~255不同的数值,看看不同透明度的值的效果有何不同。

当透明度为127,即半透明,效果如下图所示:

这里写图片描述

当透明度为255,即完全不透明,效果如下图所示:

这里写图片描述

当透明度为0,即完全透明,效果如下图所示:

这里写图片描述

代码地址

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值