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

来源:互联网 发布:网络暴力乔任梁议论文 编辑:程序博客网 时间:2024/06/05 10:27

本篇来讲解一些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