您的位置:首页 > 移动开发 > Android开发

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

2017-06-03 23:09 405 查看
本篇来讲解一些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,即完全透明,效果如下图所示:



代码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android