The Android framework provides a set of two-dimensional drawing APIs that allow you to render your own custom graphics onto a canvas or to modify existing views to customize their look and feel. You typically draw 2-D graphics in one canvas to the appropriate class'
onDraw(Canvas)method. You can also use the drawing methods in
Canvas. This option also puts you in control of any animation.
Drawing to a view is a good choice when you want to draw simple graphics that don't need to change dynamically and. However, there's more than one way to do this:
- In your app's main thread, wherein you create a custom view component in your layout, call
invalidate()and then handle the
onDraw(Canvas)callback.
- In a worker thread that manages a
SurfaceView, use drawing methods of the canvas. You don't need to call
invalidate().
Draw with a canvas
You can meet the requirements of an app that needs specialized drawing and/or
control of the graphics animation by drawing to a canvas, which is
represented by the
Canvas class. A canvas serves as a
pretense, or interface, to the actual surface upon which your graphics are
drawn—you can perform your draw operations to the canvas. Via the
canvas, your app draws to the underlying
Bitmap object,
which is placed into the window.
If you're drawing within the
onDraw(Canvas)
callback, the canvas is already provided and you only need to place your drawing
calls upon it. If you're using a
SurfaceView object, you
can acquire a canvas from
lockCanvas(). Both
of these scenarios are discussed in the following sections.
If you need to create a new
Canvas object, then you
must define the underlying
Bitmap object that is
required to place the drawing into a window. The following code example shows
how to set up a new canvas from a bitmap:
Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(b);
It's possible to use the bitmap in a different canvas by using one of the
drawBitmap() methods. However, we
recommend that you use a canvas provided by the
onDraw(Canvas) callback or the
lockCanvas() method. For more information, see Drawing on a View and Drawing on a
SurfaceView.
The
Canvas class has its own set of drawing methods,
including
drawBitmap(),
drawRect(),
drawText(), and many more. Other classes that
you might use also have
draw() methods. For example, you probably
have some
Drawable objects that you want to
put on the canvas. The
Drawable class has its own
draw(Canvas) method that takes your canvas
as an argument.
Drawing on a view
If your app doesn't require a significant amount of processing or a high
frame rate (for example a chess game, a snake game, or another slowly animated
app), then you should consider creating a custom view and drawing
with a canvas in the
View.onDraw(Canvas) callback. The most convenient aspect of this is that
the Android framework provides a predefined canvas that can perform your
drawing operations.
To start, create a subclass of
View and implement the
onDraw(Canvas) callback, which the Android framework
calls to draw the view. Then perform the draw operations through the
Canvas object, which is provided by the framework.
The Android framework only calls
onDraw(Canvas) when
necessary. When it's time to redraw your app, you must invalidate the view by
calling
invalidate(). Calling
invalidate() indicates that you'd like your view to be drawn.
Android then calls your view's
onDraw(Canvas) method, though the
call isn't guaranteed to be instantaneous.
Inside your view's
onDraw(Canvas) method, call drawing
methods on the canvas or on other classes' methods that can take your canvas as
an argument. Once your
onDraw() finishes, the Android framework
uses your canvas to draw a bitmap that is handled by the system.
Note: To invalidate a view from a thread other
than the app's main thread, you must call
postInvalidate() instead of
invalidate().
For information about extending the
View class, read
Creating a view class.
Drawing on a SurfaceView
SurfaceView is a special subclass of
View that offers a dedicated drawing surface within the view
hierarchy. The goal is to offer this drawing surface to an app's worker thread.
This way, the app isn't required to wait until the system's view hierarchy is
ready to draw. Instead, a worker thread that has a reference to a
SurfaceView object can draw to its own canvas at its own pace.
To begin, you need to create a new class that extends
SurfaceView. This class should also implement the
SurfaceHolder.Callback interface, which provides events that
happen in the underlying
Surface object, such as when it's
created, changed, or destroyed. These events let you know when you can start
drawing, whether you need to make adjustments based on new surface properties,
and when to stop drawing and potentially terminate some tasks. The class that
extends
SurfaceView is also a good place to define your worker
thread, which calls all the drawing procedures in your canvas.
Instead of handling the
Surface object directly, you
should handle it via a
SurfaceHolder. After your
SurfaceView object is initialized, you can get a
SurfaceHolder object by calling
getHolder(). You should register your
SurfaceView object to receive notifications from the
SurfaceHolder by calling
addCallback().
Then implement each
SurfaceHolder.Callback abstract method
in your
SurfaceView class.
You can draw to the surface canvas from a worker thread that has access to a
SurfaceHolder object. Perform the following steps from
inside the worker thread every time your app needs to redraw the surface:
- Use
lockCanvas()to retrieve the canvas.
- Perform drawing operations on the canvas.
- Unlock the canvas by calling
unlockCanvasAndPost(Canvas)passing the
Canvasobject that you used for your drawing operations.
The surface draws the canvas considering all the drawing operations you performed on it.
Note: Every time you retrieve the canvas from
the
SurfaceHolder, the previous state of the canvas is
retained. In order to properly animate your graphics, you must repaint the
entire surface. For example, you can clear the previous state of the canvas by
filling in a color using the
drawColor() method or setting a background image using the
drawBitmap()
method. Otherwise, your canvas could show traces of previous drawings.
Drawables
The Android framework offers a custom 2-D graphics library for drawing shapes
and images. The
android.graphics.drawable package contains common
classes used for drawing in two dimensions.
This section discusses the basics of using drawable objects to draw graphics
and how to use a couple of subclasses of the
Drawable class. For information on how to use
drawables for frame-by-frame animation, see Drawable
Animation.
A
Drawable is a general abstraction for
something that can be drawn. The Android framework offers a set of direct
and indirect
subclasses of
Drawable that you can use in a variety of scenarios.
You can also extend these classes to define your own custom drawable objects
that behave in unique ways.
There are two ways to define and instantiate a
Drawable besides using the standard class
constructors:
- Using an resource image saved in your project.
- Using an XML resource that defines the drawable properties.
Creating, as shown in the following
example:
Resources res = mContext.getResources(); Drawable myImage = res.getDrawable(R.drawable.my_image);.
Creating:
Resources res = mContext.getResources(); TransitionDrawable transition = (TransitionDrawable) res.getDrawable(R.drawable.expand_collapse);:
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()); // If the color isn't set, the shape uses black as the default. mDraw:
CustomDrawableView mCustomDrawableView; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mCustomDrawableView = new CustomDrawableView(this); setContentView(mCustom_0<<_1<<
Figure 2: Buttons rendered using an XML resource and a NinePatch graphic
Vector drawables
A vector drawable is a vector graphic defined in an XML file as a set of
points, lines, and curves along with its associated color information. The
Android framework provides the
VectorDrawable and
AnimatedVectorDrawable classes, which support
vector graphics as drawable resources.
Apps that target Android versions lower than 5.0 (API level 21) can use the Support Library version 23.2 or higher to get support for vector drawables and animated vector drawables. For more information about using the vector drawable classes, see Vector Drawable.