画布和绘图(Canvas and Drawables)

Canvas

Android 框架API提供了2D绘图,你可以渲染,绘制你的图像,当然也可以对存在的View继续外观绘制,你想要的,在进行2D图像绘制时,通常会选择如下两种方法之一:
a.绘制你的图像或者动画到布局中的视图对象。用这种方法,由系统正常的视图层次结构绘制进程进行处理你的图像绘制—你只要将你自定义的图像放到View中就行。
b.直接在Canvas(画布)上绘制你的图像。这个方法,你自己告诉对应类的onDraw()方法(传递你的画布),or one of the Canvas draw…() methods (like drawPicture()).在这种情况下,你也需要控制任一的动画。

a与b的选择:
选择a绘制你的View:

  • 你仅仅想要绘制图像,而不需要动态效果的情况;
  • 不是组成性能密集型游戏的一部分;

选择b绘制你的View:

  • 在画布中绘制,你的应用需要频繁的去重绘自己,b是最后的选择。 例如:view games 需要在自己的画布中绘制。
  • 与你得UIActivity共用一个线程,在布局中使用你自定义的View控件,调用invalidate()方法,然后处理onDraw()回调。
  • 或者,在分离的线程中,其中你管理一个SurfaceView并执行您的线程能够尽快画到画布上(你不需要在通过invalidate()方法进行请求)。

Draw with a Canvas

当你写一个应用程序,其中你想进行专业绘图和/或控制图形的动画,通过绘图画布,你应该这样做。
如果你绘制在onDraw()的回调方法中。为你提供画布和你仅需要绘制在画布上。你也可以从SurfaceHolder.lockCanvas()请求得到。然而,如果你需要创建一个新的画布,你必须自定义Bitmap,绘制将自然被执行。位图总是必须要一个画布,你可以像如下一样:

Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);

现在你的画布将在位图之上进行绘制。你可以将你的位图放到另一个湖北中去通过Canvas.drawBitmap(Bitmap,…)方法。推荐你最好绘制在通过由View.onDraw() or SurfaceHolder.lockCanvas()得到的画布绘制你最终的图像。
Canvas类你可以任意使用它所提供的方法像drawBitmap、drawRect、drawText等等。其他的类你可能也会使用到draw()方法,以你的画布作为参数。

On a View

如果你的应用不需要大量的处理或者帧率(也许是一场象棋,贪吃蛇游戏,或一个慢慢动画应用程序),那么你需要考虑创建一个自定义的视图控件或者在View.onDraw()的画布中绘制,这样做的最方便的方面是,Android框架将为您提供一个预定义的画布,你会将你的绘图调用。
开始,你的视图控件继承View,重写onDraw()方法,这个方法将被android控件请求调用,视图将绘制自己。This is where you will perform all your calls to draw through the Canvas, which is passed to you through the onDraw() callback.
每次你的应用准备好绘制,你必须请求你的视图调用invalidate()。
Note: In order to request an invalidate from a thread other than your main Activity’s thread, you must call postInvalidate().
On a SurfaceView
作为View的子类,在视图层次结构中拥有专门的绘制层。且拥有自己独立的线程,因此无需当心UI进程卡死。因此无需等待系统视图层次准备好了再继续绘制。
开始,你视图控件继承SurfaceView,且需要实现SuerfaceView.Callback,这些接口的实现方法,将用于告知一些基本的信息,例如created, changed, or destroyed.这些时间是非常重要的。
而不是直接操作Surface对象,你需要经过SurfaceHolder继续操作。所以,当你SurfaceView被初始化,通过getHolder()得到SurfaceHolder。你需要通知SurfaceHolder,通过回调addCallback()你将收到SuerfaceHolder的回调(从SurfaceHolder.Callback)。因此呢,在你的SuerfaceView类中需要重写SurefaceHolder.Callback方法。
为了在此线程中绘制到Surface Canvase,你必须通过SurfaceHandler和通过lockCanvas()取得。每次绘制都需要调用lockCanvas()得到Canvas进行绘制如果绘制完成需要调用unlockCanvasAndPost(),现在绘制画布表面时的状态。执行此锁定和解锁画布每次要重绘。

Note: On each pass you retrieve the Canvas from the SurfaceHolder, the previous state of the Canvas will be retained. In order to properly animate your graphics, you must re-paint the entire surface. For example, you can clear the previous state of the Canvas by filling in a color with drawColor() or setting a background image with drawBitmap(). Otherwise, you will see traces of the drawings you previously performed.

Drawables

Android提供了自定义2D图像库用于绘制图像,将用到android.graphics.drawable包,里面有你所需的东西。
这里主要讲解使用Drawable对象去绘制图像,和使用一些Drawable的子类。利用Drawables去实现帧动画。
Drawable是一个抽象类,你会发现,其子类有各种各样的绘制图像,包括BitmapDrawable, ShapeDrawable, PictureDrawable, LayerDrawable, and several more.当然,你也可以通过继承Drawable来实现自己想要的Drawable对象。
有三种方法进行自定义:1.用一张图片保存在你工程的资源目录中;2.使用XML文件自定义Drawable;3.使用平常的类继续构造。
三种定义方法具体做法:

  1. Creating from resource
  2. Creating from resource XML

你可以在res/drawable/目录下创建一个资源文件.xml,来定义你自己的Drawable,当然,得到这资源或者实例化可以通过Resources.getDrawable(),通过它得到此资源的ID。
任何的Drawable的子类都支持inflate()方法能够在XML中被定义和实例化,在你的应用中。每个Drawable支持XML填充,利用XML attributes帮助定义对象的属性。
例子
这里利用xml定义一个TranstionDrawable:
画布和绘图(Canvas and Drawables)_第1张图片
将其xml保存在res/drawable/下,可取名为expand_collapse.xml,接下来将在代码中使用此Drawable文件:
画布和绘图(Canvas and Drawables)_第2张图片
此时你可以设置下过渡时间,让代码中用到的这两张图片有间隔的切换
这里写图片描述

Shape Drawable

ShapeDrawable是Drawable的一个拓展,你可以用于设置View的背景通过setBackgroundDrawable()方法,当然你也可以绘制你自己的形状到你自定义的View中。ShapeDrawable拥有自己的draw()方法,你可以创建一个View的子类,然后将ShapeDrawable绘制于View的onDraw(Canvas canvas)中。具体代码如下:

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);
      }
      }

然后你可以在Activity中直接设置内容视图

CustomDrawableView mCustomDrawableView;
protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      mCustomDrawableView = new CustomDrawableView(this);
      setContentView(mCustomDrawableView);
}

或者在布局中设置:

<com.example.shapedrawable.CustomDrawableView
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      />

Ok,这样运行下,将显示出一个椭圆形

此文章翻译于androidAPI文档,如有翻译不要请见谅。

你可能感兴趣的:(Android)