分类: 嵌入式
2012-09-07 10:39:20
一. Android 图形系统
本着知其然,要知其所以然的精神,我探索了Android的图形系统。Android 的图形系统采用client/server架构。Server端(SurfaceFlinger)主要由C++代码编写而成。Client 端代码分为两部分, 一部分是由Java提供的供应用使用的api, 另一部分则是由C++写成的底层实现。Android 图形系统的框架如下图,下面我就介绍几个概念.
Application |
|
Java View/widgets/canvas |
opengl |
surface |
Skia 作为Android的图形系统,由如下特征
· 高度优化的软件 rasteriser (module sgl/)
· 选择性透过 OpenGL/ES,加速特定操作,如 shader 与 textures (module gl/)
· 动画处理能力(module animator/)
· 内建 SVG 支援 (module (svg/)
· 内建若干 image codec,如 PNG, JPEG, GIF, BMP (modules images/)
· 内建文字处理,但缺乏泰文、藏文一类复杂文字处理的能力
· 效能特性:
· 对 image 与特定数据型态的 Copy-on-write
· 内部存储器管理,谨慎地被免 fragmentation
· Thread-safety
SurfaceFlinger
SurfaceFlinger 在整个图形系统中担任 server 角色,它负责将各个 surface 根据 Z order 合成 (composer) 起来。
Surface
Android图形系统中一个重要的概念和线索是surface。View及其子类(如 TextView, Button)要画在surface上。每个surface创建一个Canvas对象(但属性时常改变),用来管理view在surface上的绘图操作,如画点画线。每个 canvas对象对应一个bitmap,存储画在surface上的内容。
每个Surface通常对应两个buffer,一个front buffer, 一个back buffer。其中, back buffer就是canvas绘图时对应的bitmap (研究 android _view_Surface.cpp::lockCanvas)。因此,绘画总是在back buffer上,需要更新时,则将back buffer和front buffer互换。
除了surfaceviews, 具有相同的vievroot的view 共享surface
Layer
surface又对应一个layer, SurfaceFlinger负责将各个layer的front buffer合成(composite)绘制 到屏幕上。
具体想进一步了解图形系统可以参看Android图形系统。
总结: 理解Android 图形系统,对于编写Android 图形程序是有帮助的。当然想换个图形引擎的话,就不是那么简单,图形系统代码多达十万行左右,没有一定的功底是无法胜任的。
二 图形系统应用
编写图形应用,我遵循了明确需求,建立模型,编写核心算法,实现功能的软件工程方法。
(1) 明确需求: 实现浏览图片时的酷眩效果。如下图
1. 向下触屏时,图片由上而下逐渐变大。
2. 向上触屏时,图片由下而上逐渐变小。
3. 向右触屏时,每张图片有向右滑出手机屏幕的动作。同时有新的系列图片从屏幕左边飞进来。同样向左边触屏,动作, 方向与向右屏幕相反。
4. 当点击某个图片的时候,图片放大,同时透明度达到最大。
(2) 建立模型
1. 定义图片集合(目前一个屏幕五个图形)
定义 private int[] mImageIds = { R.drawable.gallery_photo_1,
R.drawable.gallery_photo_2, R.drawable.gallery_photo_3,
R.drawable.gallery_photo_4, R.drawable.gallery_photo_5 };
每次触屏时,更换数组的数据,达到更新图片数据的目的.
2. 定义方向
根据触摸的坐标值来判断上下左右.
3. 计算图片间的间隙以及伸缩,透明度比例
4. 采用Animation实现图片飞进,飞出的效果。
(3) 编写核心算法
目前仅实现了图片伸缩,以及透明度变化,代码如下
private void drawBitmap(Canvas canvas, int i, float diffScale, int diffAlpha) {
int offset = myposition - i;
if (offset != 0) {
int alpha = 255 - Math.abs(offset) * 50 + diffAlpha;
mPaint.setAlpha(alpha > 255 ? 255 : alpha);
float scale = getScale(offset); // 根据不同位置的offset计算出缩放比例
scale = scale * diffScale;
// scale = (scale > 1 ? 1 : scale);
matrix.postScale(scale, scale);
} else {
mPaint.setAlpha(255);
}
Bitmap bp = BitmapFactory.decodeResource(ctx.getResources(),
mImageIds[i]);
canvas.drawBitmap(bp, matrix, mPaint);
matrix.reset();
}
鼠标控制
if (event.getAction() == event.ACTION_DOWN) {
return true;
}
if (event.getAction() == event.ACTION_MOVE) {
int p = (int) ((event.getY() - downPointY) / 5);
direction = (p > 0) ? 1 : -1;
diffScale += 0.01;
diffAlpha += 10;
this.invalidate();
return true;
}
if (event.getAction() == event.ACTION_UP) {
diffScale = 1;
diffAlpha = 0;
direction = 0;
this.invalidate();
Log.i("TAG", "up");
return true;
}
(4) 实现功能
哈,顺着我的思路做下去,实现功能不会很难了。 接下来你可能想到优化了, 提高性能了…