使用位图
加载和检查位图:Bitmap类我们可通过BitmapFactory单元素就可以从文件加载位图。
由于我们将图像以资源形式储存,因此我们从assets/目录加载一幅图像。
InputStream inputStream = assetManager.open("bob.png");
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
我们可以通过一下方法获取图像的像素宽度和高度:
int width = bitmap.getWidth();
int height = bitmap.getHeight();
接下来我们想知道是以什么样的颜色格式来存储位图:
Bitmap.Config config = bitmap.getConfig();
Bitmap.Config是一个枚举,其值如下:
Config.ALPHA_8 Config.ARGB_4444 Config.ARGB_8888 Config.RGB_565
我们可尝试使用BitmapFactory以一个特定的颜色格式来加载一幅图像,甚至是它的原始格式不同。
InputStream inputStream = assetManager.open("bob.png");
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_4444;
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);
我们可以通过BitmapFactory.Options.inPreferredConfig成员来为Bitmap实例指定一个所需的颜色格式。在这里,bob.png文件是ARGB888格式的PNG图像,我们可通过BitmapFactory加载它并将其转换成ARGB444位图。
也可以使用下面的静态方法来创建一个空的Bitmap实例:
Bitmap bitmap = Bitmap.createBitmap(int width, int height, Bitmap.Config config);
Canvas类也可以操作位图:
Canvas canvas = new Canvas(bitmap);
我们通过下面办法释放任何不再需要的位图:
Bitmap.recycle();
一旦我们加载位图,就可以通过Canvas来绘制,最简单的办法如下:
canvas.drawBitmap(Bitmap bitmap, float topLeftX, float topLeftY, Paint paint);
第二和第三个参数用于指定位图位于屏幕左上角的坐标。最后一个参数可以设置为null,也可以通过Paint来指定一下高级的绘制参数。
还有一个方法:
canvas.drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint);
这个方法非常有用,它允许我们通过第二个参数绘制指定的部分为图。Rect类保存一个矩形的左上角和右下角坐标。当我们通过第二个参数src来指定部分位图时,将会在位图的坐标系统内进行绘制,如果指定为null,那么将使用整个位图。
第三个参数定义了部分为图将要绘制在什么地方,同样采用Rect实例的形式。不过这一次的角坐标将通过Canvas上的目标对象的坐标系统来给定(一个视图或者另一个视图)。无论目标矩形比源矩形大还是小,Canvas都会做出调整。最后一个参数通常设置为null。不过这个缩放代价很大,只有在绝对必要的时候使用它。
现在看看测试代码:
package org.example.ch04_android_basics; import java.io.IOException; import java.io.InputStream; import android.app.Activity; import android.content.Context; import android.content.res.AssetManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Rect; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.Window; import android.view.WindowManager; public class BitmapTest extends Activity { class RenderView extends View{ Bitmap bob565; Bitmap bob4444; Rect dst = new Rect(); public RenderView(Context context){ super(context); try{ AssetManager assetManager = context.getAssets(); InputStream inputStream = assetManager.open("bobrgb888.png"); bob565 = BitmapFactory.decodeStream(inputStream); inputStream.close(); Log.d("BitmapText", "bobrgb888.png format: " + bob565.getConfig()); inputStream = assetManager.open("bobargb8888.png"); BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.ARGB_4444; bob4444 = BitmapFactory .decodeStream(inputStream, null, options); inputStream.close(); Log.d("BitmapText", "bobargb8888.png format: " + bob4444.getConfig()); }catch(IOException e){ // silently ignored, bad coder monkey, baaad! }finally{ // we should really close our input streams here. } } protected void onDraw(Canvas canvas){ dst.set(50, 50, 350, 350); canvas.drawBitmap(bob565, null, dst, null); canvas.drawBitmap(bob4444, 100, 100, null); invalidate(); } } @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState);
// 将窗口设置为全屏
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(new RenderView(this));
}
}
运行效果:
渲染文本
在游戏中文本信息的输出我们可以手动绘制,现在让我们从assets/目录中加载一个自定义的TrueType字体文件。
Typeface font = Typeface.createFromAsset(context.getAssets(), "font.ttf");
如果加载失败不会抛出任何异常,而是抛出一个RuntimeException
一旦获得字体,可将其设置为Paint实例的Typeface:
paint.setTypeFace(font);
通过Paint实例设置字体大小:
paint.setTextSize(30);
最后可通过下面的Canvas方法将文本以这种字体绘制出来:
canvas.drawText("This is a test!", 100, 100, paint);
显而易见,第一个参数是要绘制的文本,接下来两个参数是绘制文本的坐标位置,最后一个是Paint实例
Paint类有个方法可以设置对齐方式:
Paint.setTextAlign(Paint.Align align);
其中Paint.Align枚举有3个值:Paint.Align.LEFT、Paint.Align.CENTER、Paint.Align.RIGHT。根据对齐方式传递到Canvas.drawText()方法。标准的对齐方式是Paint.Align.LEFT。
Paint类还有一种方法可以设置字符串边界:
Paint.setTextBounds(String test, int start, int end, Rect bounds);
第二个参数和第三个参数指定进行度量的字符串的开始字符和结束字符。最后一个参数是一个Rect实例,该方法将把边框矩形的宽度和高度写进Rect.right和Rect.bottom这两个字段。为了方便,我们调用Rect.width()和Rect.height()来获得同样的值。
下面是测试代码:
package org.example.ch04_android_basics; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.Typeface; import android.os.Bundle; import android.view.View; import android.view.Window; import android.view.WindowManager; public class FontTest extends Activity { class RenderView extends View{ Paint paint; Typeface font; Rect bounds = new Rect(); public RenderView(Context context){ super(context); paint = new Paint(); font = Typeface.createFromAsset(context.getAssets(), "font.ttf"); } protected void onDraw(Canvas canvas){ paint.setColor(Color.YELLOW); paint.setTypeface(font); paint.setTextSize(28); paint.setTextAlign(Paint.Align.CENTER); canvas.drawText("This is a test!", canvas.getWidth() / 2, 100, paint); String text = "This is another test o_O"; paint.setColor(Color.CYAN); paint.setTextSize(18); paint.setTextAlign(Paint.Align.LEFT); paint.getTextBounds(text, 0, text.length(), bounds); canvas.drawText(text, canvas.getWidth() - bounds.width(), 140, paint); invalidate(); } } @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(new RenderView(this)); } }运行效果: