Canvas and Drawable
当想要画2D图形时,典型的有两种方式:
a. 通过Layout把图形或者动画 draw 到一个View对象中。这种方式比较适合画一个简单的图形不需要动态变化并且不是高性能的游戏。通过Drawables了解更详细的信息。
b. 直接把图形画到Canvas上。这种方式,你需要亲自调用相关类的onDraw()方法 或者 Canvas类中的任一个draw开头的方法(像drawPicture())。
- 如果在UI thread中,你在Layout中创建了一个自定义View,调用invalidate() 方法然后处理onDraw() callback。
- 或者, 不在UI thread, wherein you manage a SurfaceView and perform draws to the Canvas as fast as your thread is capable (you do not need to request invalidate()).
Draw with a Canvas
Canvas类拥有很多”draw” 方法. 想要绘制,需要4个基础组件: A Bitmap to hold the pixels, a Canvas to host the draw calls (writing into the bitmap), a drawing primitive (e.g. Rect, Path, text, Bitmap), and a paint (to describe the colors and styles for the drawing).
On a View
继承View并且覆写onDraw()回调方法,这个方法将被Android Framework调用去请求view绘制自己。View中的绘制工作都通过onDraw回调方法中的Canvas用来执行。
Android framework会在必要的时候调用onDraw方法。每次你的应用准备去被绘制的时候,你必须通过调用invalidate(如果不是主线程、则需要调用postInvalidate)方法来请求你的View被无效。这个表示你想要你的View被绘制并且Android将会调用View的onDraw方法。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mBitmap != null) {
canvas.drawBitmap(mBitmap, 0, 0, null);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
... ...
invalidate();
return true;
}
On a SurfaceView
通过SurfaceView,首先要创建一个新类继承SurfaceView同时也应该实现SurfaceHolder.Callback。 这个回调函数是一个用来通知你关于Surface相关的信息,比如它什么时候被创建、改变或者销毁。
我们应该通过使用SurfaceHolder来替换直接操作Surface对象。所以,当SurfaceView被初始化后通过调用getHolder来获取SurfaceHolder 。你应该通知SurfaceHolder 你想要接收SurfaceHolder callbaks通过调用addCallback()。
为了能够在别的线程中绘制到这个Surface Canvas中,必须传递SurfaceHolder然后通过lockCanvas来获取Canvas。当完成绘制工作后通过调用unlockCanvasAndPost把绘制内容传递到Canvas中。这个Surface将会绘制刚才那个Canvas。每次你想重绘制的时候都需要这么执行这个locking and unlocking的顺序
Drawables
Drawable类定义了好多特定类型的drawable图形,包括了:BitmapDrawable, ShapeDrawable, PictureDrawable, LayerDrawable等等。下面是两种定义和使用的方式:
Creating from resource images
通过image资源来创建,只需把需要用的image,放置到res/drawable/ 目录下, 然后通过R.drawable.my_image来访问。(在res/drawable/ 目录下的图片资源会被aapt压缩优化,如果需要使用原图片的字节流,请把图片放到res/raw目录下)
Creating from resource XML
通过XML资源来创建,一旦把Drawable定义在XML中,把文件保存在“res/drawable/”目录下,然后通过“Resources.getDrawable()”获取Drawable对象。
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/image_expand">
<item android:drawable="@drawable/image_collapse">
</transition>
Resources res = mContext.getResources();
TransitionDrawable transition = (TransitionDrawable)
res.getDrawable(R.drawable.expand_collapse);
ImageView image = (ImageView) findViewById(R.id.toggle_image);
image.setImageDrawable(transition);
Shape Drawable
当你想要动态的绘制一些二维图形时,ShapeDrawable可以满足这个需求。ShapeDrawable可以编程的方式绘制原始的图形并且进行样式化。
ShapeDrawable主要包含三个主要的组件:Shape、Paint和Bounds。一定要调用setBounds方法,要不然shape不会被绘制。
public class CustomDrawableView extends View {
private ShapeDrawable mDrawable;
public CustomDrawableView(Context context) {
super(context);
int x = 10;
int y = 10;
int width = 300;
int height = 50;
mDrawable = new ShapeDrawable(new OvalShape());
mDrawable.getPaint().setColor(0xff74AC23);
mDrawable.setBounds(x, y, x + width, y + height);
}
protected void onDraw(Canvas canvas) {
mDrawable.draw(canvas);
}
}