第 9 章 2D 图形接口的使用
9.6 记录绘制的过程
9.1 使用 2D 图形接口的程序结构 9.2 图像、图形、文本的基本绘制 9.3 文本的对齐方式
9.4 使用路径效果 (PathEffect) 9.5 剪裁效果
9.6 记录绘制的过程 9.7 动画效果
在 GUI 系统中,图形 API 是比较底层的接口。Android 系统的图形 API 包括 2D 和 3D 两部分:2D 部分使 用 android.graphics 类,也作为上层控件的构建基础;3D 部分使用 OpenGL 作为标准接口。
9.1 使用 2D图形接口的程序结构。
2D 图形的接口实际上是 Android 图形系统的基础, GUI 上的各种可见元素也是基于 2D 图形接口构建的。
因此,Android GUI 方面的内容分为两层,下层是图形的 API,上层是各种控件,各种控件实际上是基于图形 API 绘制出来的。
使用 2D 图形接口的结构如下图所示:
android.view.View
MYView ::onDraw(Canvas canvas) User Application
android.graphics.Canvas ( Graphics / Text / Bitmap ) android.Widget.XXX
图 Android 2D 绘图接口结构
通过继承 android.view.View 类,并实现其中的 onDraw()函数来实现绘制的工作,绘制的工作主要由 android.graphics 包来实现。android.graphics 包中的内容是 Android 系统的 2D 图形 API,其中主要类的内容包含 以下一些内容:
Point、Rect 和 Color 等:一些基础类,分别定义顶点、矩阵、颜色的基础信息元素;
Bitmap:表示内存中的位图,可以从图像文件中建立,可以指定依靠颜色来建立,也可以控制其中的每一 个像素;
Paint:画笔,用于控制绘制的样式(style)和颜色(color)等信息;
Canvas:画布,2D 图形系统最核心的一个类,处理 onDraw()调用
void drawCircle(float cx, float cy, float radius, Paint paint) // 绘制圆形 void drawArc(RectF oval, float startAngle, float sweepAngle, // 绘制圆弧 boolean useCenter, Paint paint)
Canvas 类的文本(Text)方面的方法用于直接绘制文本内容,文本通常用一个字符串来表示。其中一些主 要的方法如下所示:
void drawText(String text, int start, int end, float x, float y, Paint paint) void drawText(char[] text, int index, int count, float x, float y, Paint paint) void drawText(String text, float x, float y, Paint paint)
void drawText(CharSequence text, int start, int end, float x, float y, Paint paint)
Canvas 类的位图(Bitmap)方面的方法用于直接绘制位图,位图通常用一个 Bitmap 类来表示。其中一些 主要的方法如下所示:
void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) // 指定 Matrix 绘制位图 void drawBitmap(int[] colors, int offset, int stride, // 指定数组作为 Bitmap 绘制 float x, float y, int width, int height,
boolean hasAlpha, Paint paint)
void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint)// 自动缩放到目标矩形的绘制
Canvas 是 Android 的 2D 图形绘制的中枢,绘制方法的参数中通常包含一个 Paint 类型,它作为附加绘制的
android.graphics.drawable 包是 Android 中一个绘制相关的包,表示一些可以被绘制的东西。在 Android 中 Drawable 的含义就是可以仅仅是为了显示来使用的,与 View 的主要区别就在于 Drawable 不能从用户处获得事 件的反馈。
图 AlphaBitmap 程序的运行结果
本程序在界面上自上而下一共绘制了 3 个内容,第一个是一个原始位图,第二个是经过变化的位图,第三 个是几何图形。
在这个示例程序中,主要通过将一个自定义的 SampleView 设置成活动的 View 作为其中的 ContentView。
onCreate()函数如下所示:
public class AlphaBitmap extends GraphicsActivity { // GraphicsActivity 相当于 Activity @Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(new SampleView(this)); // 设置实现中的 SampleView }
}
SampleView 是其中扩展了 View 的实现,主要的内容在类的构造函数和 OnDraw()函数中,内容如下所示:
private static class SampleView extends View { private Bitmap mBitmap;
private static void drawIntoBitmap(Bitmap bm) { float x = bm.getWidth();
p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
p.setTextSize(60);
p.setTextAlign(Paint.Align.CENTER);
Paint.FontMetrics fm = p.getFontMetrics();
c.drawText("Alpha", x/2, (y-fm.ascent)/2, p);
}
@Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE);
private static class SampleView extends View { private Paint mPaint;
private static void makePath(Path p) { p.moveTo(10, 0);
p.cubicTo(100, -50, 200, 50, 300, 0);
}
private float[] buildTextPositions(String text, float y, Paint paint) { // 省略,计算位置信息等内容
canvas.drawPath(mPath, mPathPaint);
p.setTextAlign(Paint.Align.RIGHT);
canvas.drawTextOnPath(TEXTONPATH, mPath, 0, 0, p); // 绘制对齐路径的文本 }
// 省略部分内容 }
文本的对其操作主要通过以下两点来完成:
1.通过画笔(Paint)的 setTextAlign()函数设置绘制过程中的对齐方式。
2.drawText(),drawPosText(),drawTextOnPath()几个函数表示了文本的几种绘制方式。drawText()在指定 的坐标上进行文本绘制;drawPosText()在一个表示为位置信息的数组上进行文本绘制(其中的 float[] pos 参数 表示交替的 x 和 y 表示的坐标);drawTextOnPath()表示在一个路径(Path)进行文本绘制。
9.4 使用路径效果(PathEffect)
路径表示一条曲线,在 Android 中通过路径可以更灵活地实现一些效果。
参考示例程序:ApiDemo 的 PathEffects(ApiDemo=>Graphics=>PathEffects)
源代码:android/apis/graphics/PathEffects.java PathEffects 程序的运行结果如图所示:
图 PathEffects 程序的运行结果
图中的几个路径的曲线的基本走向一致,但是细节的方面各不相同,例如线的方式 代码主要是实现了 SampleView,核心部分如下所示:
private static class SampleView extends View { private Paint mPaint;
private Path mPath;
private PathEffect[] mEffects;
private int[] mColors;
private float mPhase;
private static PathEffect makeDash(float phase) {
return new DashPathEffect(new float[] { 15, 5, 8, 5 }, phase);
}
private static void makeEffects(PathEffect[] e, float phase) { e[0] = null; // 没有效果
e[1] = new CornerPathEffect(10); // 拐角路径效果 e[2] = new DashPathEffect(new float[] {10, 5, 5, 5}, phase);
e[3] = new PathDashPathEffect(makePathDash(), 12, phase, PathDashPathEffect.Style.ROTATE);
// 破折号式效果
e[4] = new ComposePathEffect(e[2], e[1]); // 组合路径效果(内外各不同)
} ComposePathEffect, CornerPathEffect, DashPathEffect, DiscretePathEffect, PathDashPathEffect, SumPathEffect。
9.5 剪裁效果
图 Clipping 程序的运行结果
图中的 6 个绘制效果各不相同,每个部分都是在一个白色矩形区域中,绘制一个条红线、一个绿色的 园和一个蓝色的文本组成。
private static class SampleView extends View { private Paint mPaint;
mPath.addCircle(50, 50, 50, Path.Direction.CCW);
boolean clipRect(float left, float top, float right, float bottom)
boolean clipRect(float left, float top, float right, float bottom, Region.Op op)
剪裁的功能可以丰富绘制的最终效果。
图 记录和重现绘制效果的运行结果 本例子的核心部分如下所示:
private static class SampleView extends View { private Picture mPicture;
Pictures 是一个可以记录绘制过程的类,通常情况下 Android 的绘制工作需要被绘制到画布(Cavans)上,
但是能显示的画布只有一个。Pictures 的功能就在于可以让绘制的东西绘制到一个虚拟的画布上,这个虚拟的 画布由 Pictures 的 beginRecording()函数返回,picture.draw(canvas)和 canvas.drawPicture()函数用于将一个记录好 的绘制过程,重现到画布上。Pictures 绘制的内容也可以被记录到一个流当中,然后在重新构造一个 Pictures。