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

本篇来讲解一些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提供这些方法是用来帮助我们简化绘图的。例如,创建如下的一个仪表盘:

这里写图片描述

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

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

第一步绘制圆盘,调用 canvas.drawCircle()方法绘制一个圆,关键在于确定圆心和半径。为了方便演示我们把圆心定在屏幕中心所以半径为屏幕宽的一半。

    //画外圆
    Paint paintCircle = new Paint();
    //FILL填充 FILL_AND_STROKE填充加描边 STROKE描边
    paintCircle.setStyle(Paint.Style.STROKE);
    //设置抗锯齿
    paintCircle.setAntiAlias(true);
    //设置画笔宽度
    paintCircle.setStrokeWidth(5);
    //params 圆心,半径  -5f为了抵消画笔宽度
    canvas.drawCircle(mWidth / 2, mHeight / 2, mWidth / 2 - 5f, paintCircle);

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

    // 画刻度与刻度线
    Paint paintDegree = new Paint();
    //从0开始画直线
    for (int i = 0; i < 24; i++) {
        if (i == 0 || i == 6 || i == 12 || i == 18) {
            //区分整点与非整点
            paintDegree.setStrokeWidth(5);
            paintDegree.setTextSize(30);
            paintCircle.setAntiAlias(true);
            //直线起点坐标为mHeight/2减去圆半径长度  +5f为抵消画笔宽度
            canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2 + 5f,
                    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);
            paintCircle.setAntiAlias(true);
            canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2 + 5f,
                    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()方法将原点坐标(0,0)移动到圆心坐标,这样再画线段的时候就可以理解为从原点开始画一条线段了。

    //画圆心
    paintPointer.setStrokeWidth(30);
    canvas.drawPoint(mWidth / 2, mHeight / 2, paintPointer);
    //画指针
    paintHour.setStrokeWidth(20);
    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上,下面是仿照Api Demos里的一个实例:

public class MyLayer extends View {

    private Paint mPaint;
    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;

    public MyLayer(Context context) {
        super(context);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.WHITE);
        mPaint.setColor(Color.BLUE);
        canvas.drawCircle(150, 150, 100, mPaint);
        //alpha 255不透明,127半透明,0全透明
        canvas.saveLayerAlpha(0, 0, 400, 400, 255, LAYER_FLAGS);
        mPaint.setColor(Color.RED);
        canvas.drawCircle(200, 200, 100, mPaint);
        canvas.restore();
    }
}

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

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

这里写图片描述

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

这里写图片描述

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

这里写图片描述

代码下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值