| page.title=Canvas and Drawables |
| parent.title=Graphics |
| parent.link=index.html |
| @jd:body |
| |
| <div id="qv-wrapper"> |
| <div id="qv"> |
| <h2>In this document</h2> |
| <ol> |
| <li><a href="#draw-with-canvas">Draw with a Canvas</a> |
| <ol> |
| <li><a href="#on-view">On a View</a></li> |
| <li><a href="#on-surfaceview">On a SurfaceView</a></li> |
| </ol> |
| </li> |
| <li><a href="#drawables">Drawables</a> |
| <ol> |
| <li><a href="#drawables-from-images">Creating from resource images</a></li> |
| <li><a href="#drawables-from-xml">Creating from resource XML</a></li> |
| </ol> |
| </li> |
| <li><a href="#shape-drawable">Shape Drawable</a></li> |
| <li><a href="#nine-patch">Nine-patch</a></li> |
| <li><a href="#vector-drawable">Vector Drawables</a></li> |
| </ol> |
| |
| <h2>See also</h2> |
| <ol> |
| <li><a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL with the Framework |
| APIs</a></li> |
| <li><a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a></li> |
| </ol> |
| </div> |
| </div> |
| |
| <p>The Android framework APIs provides a set of 2D-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. |
| When drawing 2D graphics, you'll typically do so in one of two ways:</p> |
| |
| <ol type="a"> |
| <li>Draw your graphics or animations into a View object from your layout. In this manner, |
| the drawing of your graphics is handled by the system's |
| normal View hierarchy drawing process — you simply define the graphics to go inside the View.</li> |
| <li>Draw your graphics directly to a Canvas. This way, you personally call the appropriate class's |
| {@link android.view.View#onDraw onDraw()} method (passing it your Canvas), or one of the Canvas |
| <code>draw...()</code> methods (like |
| <code>{@link android.graphics.Canvas#drawPicture(Picture,Rect) drawPicture()}</code>). In doing so, you are also in |
| control of any animation.</li> |
| </ol> |
| |
| <p>Option "a," drawing to a View, is your best choice when you want to draw simple graphics that do not |
| need to change dynamically and are not part of a performance-intensive game. For example, you should |
| draw your graphics into a View when you want to display a static graphic or predefined animation, within |
| an otherwise static application. Read <a href="#drawables">Drawables</a> for more information.</li> |
| </p> |
| |
| <p>Option "b," drawing to a Canvas, is better when your application needs to regularly re-draw itself. |
| Applications such as video games should be drawing to the Canvas on its own. However, there's more than |
| one way to do this:</p> |
| |
| <ul> |
| <li>In the same thread as your UI Activity, wherein you create a custom View component in |
| your layout, call <code>{@link android.view.View#invalidate()}</code> and then handle the |
| <code>{@link android.view.View#onDraw(Canvas) onDraw()}</code> callback.</li> |
| <li>Or, in a separate thread, wherein you manage a {@link android.view.SurfaceView} and |
| perform draws to the Canvas as fast as your thread is capable |
| (you do not need to request <code>invalidate()</code>).</li> |
| </ul> |
| |
| <h2 id="draw-with-canvas">Draw with a Canvas</h2> |
| |
| <p>When you're writing an application in which you would like to perform specialized drawing |
| and/or control the animation of graphics, |
| you should do so by drawing through a {@link android.graphics.Canvas}. A Canvas works for you as |
| a pretense, or interface, to the actual surface upon which your graphics will be drawn — it |
| holds all of your "draw" calls. Via the Canvas, your drawing is actually performed upon an |
| underlying {@link android.graphics.Bitmap}, which is placed into the window.</p> |
| |
| <p>In the event that you're drawing within the <code>{@link android.view.View#onDraw(Canvas) onDraw()}</code> |
| callback method, the Canvas is provided for you and you need only place your drawing calls upon it. |
| You can also acquire a Canvas from <code>{@link android.view.SurfaceHolder#lockCanvas() SurfaceHolder.lockCanvas()}</code>, |
| when dealing with a SurfaceView object. (Both of these scenarios are discussed in the following sections.) |
| However, if you need to create a new Canvas, then you must define the {@link android.graphics.Bitmap} |
| upon which drawing will actually be performed. The Bitmap is always required for a Canvas. You can set up |
| a new Canvas like this:</p> |
| <pre> |
| Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); |
| Canvas c = new Canvas(b); |
| </pre> |
| |
| <p>Now your Canvas will draw onto the defined Bitmap. After drawing upon it with the Canvas, you can then carry your |
| Bitmap to another Canvas with one of the <code>{@link android.graphics.Canvas#drawBitmap(Bitmap,Matrix,Paint) |
| Canvas.drawBitmap(Bitmap,...)}</code> methods. It's recommended that you ultimately draw your final |
| graphics through a Canvas offered to you |
| by <code>{@link android.view.View#onDraw(Canvas) View.onDraw()}</code> or |
| <code>{@link android.view.SurfaceHolder#lockCanvas() SurfaceHolder.lockCanvas()}</code> (see the following sections).</p> |
| |
| <p>The {@link android.graphics.Canvas} class has its own set of drawing methods that you can use, |
| like <code>drawBitmap(...)</code>, <code>drawRect(...)</code>, <code>drawText(...)</code>, and many more. |
| Other classes that you might use also have <code>draw()</code> methods. For example, you'll probably |
| have some {@link android.graphics.drawable.Drawable} objects that you want to put on the Canvas. Drawable |
| has its own <code>{@link android.graphics.drawable.Drawable#draw(Canvas) draw()}</code> method |
| that takes your Canvas as an argument.</p> |
| |
| |
| <h3 id="on-view">On a View</h3> |
| |
| <p>If your application does not require a significant amount of processing or |
| frame-rate speed (perhaps for a chess game, a snake game, |
| or another slowly-animated application), then you should consider creating a custom View component |
| and drawing with a Canvas in <code>{@link android.view.View#onDraw(Canvas) View.onDraw()}</code>. |
| The most convenient aspect of doing so is that the Android framework will |
| provide you with a pre-defined Canvas to which you will place your drawing calls.</p> |
| |
| <p>To start, extend the {@link android.view.View} class (or descendant thereof) and define |
| the <code>{@link android.view.View#onDraw(Canvas) onDraw()}</code> callback method. This method will be called by the Android |
| framework to request that your View draw itself. This is where you will perform all your calls |
| to draw through the {@link android.graphics.Canvas}, which is passed to you through the <code>onDraw()</code> callback.</p> |
| |
| <p>The Android framework will only call <code>onDraw()</code> as necessary. Each time that |
| your application is prepared to be drawn, you must request your View be invalidated by calling |
| <code>{@link android.view.View#invalidate()}</code>. This indicates that you'd like your View to be drawn and |
| Android will then call your <code>onDraw()</code> method (though is not guaranteed that the callback will |
| be instantaneous). </p> |
| |
| <p>Inside your View component's <code>onDraw()</code>, use the Canvas given to you for all your drawing, |
| using various <code>Canvas.draw...()</code> methods, or other class <code>draw()</code> methods that |
| take your Canvas as an argument. Once your <code>onDraw()</code> is complete, the Android framework will |
| use your Canvas to draw a Bitmap handled by the system.</p> |
| |
| <p class="note"><strong>Note: </strong> In order to request an invalidate from a thread other than your main |
| Activity's thread, you must call <code>{@link android.view.View#postInvalidate()}</code>.</p> |
| |
| <p>For information about extending the {@link android.view.View} class, read |
| <a href="{@docRoot}guide/topics/ui/custom-components.html">Building Custom Components</a>.</p> |
| |
| <p>For a sample application, see the Snake game, in the SDK samples folder: |
| <code><your-sdk-directory>/samples/Snake/</code>.</p> |
| |
| <h3 id="on-surfaceview">On a SurfaceView</h3> |
| |
| <p>The {@link android.view.SurfaceView} is a special subclass of View that offers a dedicated |
| drawing surface within the View hierarchy. The aim is to offer this drawing surface to |
| an application's secondary thread, so that the application isn't required |
| to wait until the system's View hierarchy is ready to draw. Instead, a secondary thread |
| that has reference to a SurfaceView can draw to its own Canvas at its own pace.</p> |
| |
| <p>To begin, you need to create a new class that extends {@link android.view.SurfaceView}. The class should also |
| implement {@link android.view.SurfaceHolder.Callback}. This subclass is an interface that will notify you |
| with information about the underlying {@link android.view.Surface}, such as when it is created, changed, or destroyed. |
| These events are important so that 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 |
| kill some tasks. Inside your SurfaceView class is also a good place to define your secondary Thread class, which will |
| perform all the drawing procedures to your Canvas.</p> |
| |
| <p>Instead of handling the Surface object directly, you should handle it via |
| a {@link android.view.SurfaceHolder}. So, when your SurfaceView is initialized, get the SurfaceHolder by calling |
| <code>{@link android.view.SurfaceView#getHolder()}</code>. You should then notify the SurfaceHolder that you'd |
| like to receive SurfaceHolder callbacks (from {@link android.view.SurfaceHolder.Callback}) by calling |
| {@link android.view.SurfaceHolder#addCallback(SurfaceHolder.Callback) addCallback()} |
| (pass it <var>this</var>). Then override each of the |
| {@link android.view.SurfaceHolder.Callback} methods inside your SurfaceView class.</p> |
| |
| <p>In order to draw to the Surface Canvas from within your second thread, you must pass the thread your SurfaceHandler |
| and retrieve the Canvas with <code>{@link android.view.SurfaceHolder#lockCanvas() lockCanvas()}</code>. |
| You can now take the Canvas given to you by the SurfaceHolder and do your necessary drawing upon it. |
| Once you're done drawing with the Canvas, call |
| <code>{@link android.view.SurfaceHolder#unlockCanvasAndPost(Canvas) unlockCanvasAndPost()}</code>, passing it |
| your Canvas object. The Surface will now draw the Canvas as you left it. Perform this sequence of locking and |
| unlocking the canvas each time you want to redraw.</p> |
| |
| <p class="note"><strong>Note:</strong> 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 <code>{@link android.graphics.Canvas#drawColor(int) drawColor()}</code> or setting a background image |
| with <code>{@link android.graphics.Canvas#drawBitmap(Bitmap,Rect,RectF,Paint) drawBitmap()}</code>. Otherwise, |
| you will see traces of the drawings you previously performed.</p> |
| |
| |
| <p>For a sample application, see the Lunar Lander game, in the SDK samples folder: |
| <code><your-sdk-directory>/samples/LunarLander/</code>. Or, |
| browse the source in the <a href="{@docRoot}guide/samples/index.html">Sample Code</a> section.</p> |
| |
| <h2 id="drawables">Drawables</h2> |
| <p>Android offers a custom 2D graphics library for drawing shapes and images. |
| The {@link android.graphics.drawable} package is where you'll find the common classes used for |
| drawing in two-dimensions.</p> |
| |
| <p>This document discusses the basics of using Drawable objects to draw graphics and how to use a |
| couple subclasses of the Drawable class. For information on using Drawables to do frame-by-frame |
| animation, see <a href="{@docRoot}guide/topics/graphics/drawable-animation.html">Drawable |
| Animation</a>.</p> |
| |
| <p>A {@link android.graphics.drawable.Drawable} is a general abstraction for "something that can be |
| drawn." You'll discover that the Drawable class extends to define a variety of specific kinds of |
| drawable graphics, including {@link android.graphics.drawable.BitmapDrawable}, {@link |
| android.graphics.drawable.ShapeDrawable}, {@link android.graphics.drawable.PictureDrawable}, |
| {@link android.graphics.drawable.LayerDrawable}, and several more. Of course, you can also extend |
| these to define your own custom Drawable objects that behave in unique ways.</p> |
| |
| <p>There are three ways to define and instantiate a Drawable: using an image saved in your project |
| resources; using an XML file that defines the Drawable properties; or using the normal class |
| constructors. Below, we'll discuss each the first two techniques (using constructors is nothing new |
| for an experienced developer).</p> |
| |
| |
| <h3 id="drawables-from-images">Creating from resource images</h3> |
| |
| <p>A simple way to add graphics to your application is by referencing an image file from your |
| project resources. Supported file types are PNG (preferred), JPG (acceptable) and GIF |
| (discouraged). This technique would obviously be preferred for application icons, logos, or other |
| graphics such as those used in a game.</p> |
| |
| <p>To use an image resource, just add your file to the <code>res/drawable/</code> directory of your |
| project. From there, you can reference it from your code or your XML layout. |
| Either way, it is referred using a resource ID, which is the file name without the file type |
| extension (E.g., <code>my_image.png</code> is referenced as <var>my_image</var>).</p> |
| |
| <p class="note"><strong>Note:</strong> Image resources placed in <code>res/drawable/</code> may be |
| automatically optimized with lossless image compression by the |
| <code>aapt</code> tool during the build process. For example, a true-color PNG that does |
| not require more than 256 colors may be converted to an 8-bit PNG with a color palette. This |
| will result in an image of equal quality but which requires less memory. So be aware that the |
| image binaries placed in this directory can change during the build. If you plan on reading |
| an image as a bit stream in order to convert it to a bitmap, put your images in the |
| <code>res/raw/</code> folder instead, where they will not be optimized.</p> |
| |
| <h4>Example code</h4> |
| <p>The following code snippet demonstrates how to build an {@link android.widget.ImageView} that |
| uses an image from drawable resources and add it to the layout.</p> |
| <pre> |
| LinearLayout mLinearLayout; |
| |
| protected void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| |
| // Create a LinearLayout in which to add the ImageView |
| mLinearLayout = new LinearLayout(this); |
| |
| // Instantiate an ImageView and define its properties |
| ImageView i = new ImageView(this); |
| i.setImageResource(R.drawable.my_image); |
| i.setAdjustViewBounds(true); // set the ImageView bounds to match the Drawable's dimensions |
| i.setLayoutParams(new Gallery.LayoutParams(LayoutParams.WRAP_CONTENT, |
| LayoutParams.WRAP_CONTENT)); |
| |
| // Add the ImageView to the layout and set the layout as the content view |
| mLinearLayout.addView(i); |
| setContentView(mLinearLayout); |
| } |
| </pre> |
| <p>In other cases, you may want to handle your image resource as a |
| {@link android.graphics.drawable.Drawable} object. |
| To do so, create a Drawable from the resource like so: |
| <pre> |
| Resources res = mContext.getResources(); |
| Drawable myImage = res.getDrawable(R.drawable.my_image); |
| </pre> |
| |
| <p class="warning"><strong>Note:</strong> Each unique resource in your project can maintain only |
| one state, no matter how many different objects you may instantiate for it. For example, if you |
| instantiate two Drawable objects from the same image resource, then change a property (such |
| as the alpha) for one of the Drawables, then it will also affect the other. So when dealing with |
| multiple instances of an image resource, instead of directly transforming the Drawable, you |
| should perform a <a href="{@docRoot}guide/topics/graphics/view-animation.html#tween-animation">tween |
| animation</a>.</p> |
| |
| |
| <h4>Example XML</h4> |
| <p>The XML snippet below shows how to add a resource Drawable to an |
| {@link android.widget.ImageView} in the XML layout (with some red tint just for fun). |
| <pre> |
| <ImageView |
| android:layout_width="wrap_content" |
| android:layout_height="wrap_content" |
| android:tint="#55ff0000" |
| android:src="@drawable/my_image"/> |
| </pre> |
| <p>For more information on using project resources, read about |
| <a href="{@docRoot}guide/topics/resources/index.html">Resources and Assets</a>.</p> |
| |
| |
| <h3 id="drawables-from-xml">Creating from resource XML</h3> |
| |
| <p>By now, you should be familiar with Android's principles of developing a |
| <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a>. Hence, you understand the |
| power and flexibility inherent in defining objects in XML. This philosophy caries over from Views |
| to Drawables. If there is a Drawable object that you'd like to create, which is not initially |
| dependent on variables defined by your application code or user interaction, then defining the |
| Drawable in XML is a good option. Even if you expect your Drawable to change its properties |
| during the user's experience with your application, you should consider defining the object in |
| XML, as you can always modify properties once it is instantiated.</p> |
| |
| <p>Once you've defined your Drawable in XML, save the file in the <code>res/drawable/</code> |
| directory of your project. Then, retrieve and instantiate the object by calling |
| {@link android.content.res.Resources#getDrawable(int) Resources.getDrawable()}, passing it the |
| resource ID of your XML file. (See the <a href="#drawable-xml-example">example |
| below</a>.)</p> |
| |
| <p>Any Drawable subclass that supports the <code>inflate()</code> method can be defined in |
| XML and instantiated by your application. Each Drawable that supports XML inflation utilizes |
| specific XML attributes that help define the object |
| properties (see the class reference to see what these are). See the class documentation for each |
| Drawable subclass for information on how to define it in XML. |
| |
| <h4 id="drawable-xml-example">Example</h4> |
| <p>Here's some XML that defines a TransitionDrawable:</p> |
| <pre> |
| <transition xmlns:android="http://schemas.android.com/apk/res/android"> |
| <item android:drawable="@drawable/image_expand"> |
| <item android:drawable="@drawable/image_collapse"> |
| </transition> |
| </pre> |
| |
| <p>With this XML saved in the file <code>res/drawable/expand_collapse.xml</code>, |
| the following code will instantiate the TransitionDrawable and set it as the content of an |
| ImageView:</p> |
| <pre> |
| Resources res = mContext.getResources(); |
| TransitionDrawable transition = (TransitionDrawable) |
| res.getDrawable(R.drawable.expand_collapse); |
| ImageView image = (ImageView) findViewById(R.id.toggle_image); |
| image.setImageDrawable(transition); |
| </pre> |
| <p>Then this transition can be run forward (for 1 second) with:</p> |
| <pre>transition.startTransition(1000);</pre> |
| |
| <p>Refer to the Drawable classes listed above for more information on the XML attributes |
| supported by each.</p> |
| |
| |
| |
| <h2 id="shape-drawable">Shape Drawable</h2> |
| |
| <p>When you want to dynamically draw some two-dimensional graphics, a {@link |
| android.graphics.drawable.ShapeDrawable} |
| object will probably suit your needs. With a ShapeDrawable, you can programmatically draw |
| primitive shapes and style them in any way imaginable.</p> |
| |
| <p>A ShapeDrawable is an extension of {@link android.graphics.drawable.Drawable}, so you can use |
| one wherever |
| a Drawable is expected — perhaps for the background of a View, set with |
| {@link android.view.View#setBackgroundDrawable(android.graphics.drawable.Drawable) |
| setBackgroundDrawable()}. |
| Of course, you can also draw your shape as its own custom {@link android.view.View}, |
| to be added to your layout however you please. |
| Because the ShapeDrawable has its own <code>draw()</code> method, you can create a subclass of |
| View that |
| draws the ShapeDrawable during the <code>View.onDraw()</code> method. |
| Here's a basic extension of the View class that does just this, to draw a ShapeDrawable as a |
| View:</p> |
| <pre> |
| 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); |
| } |
| } |
| </pre> |
| |
| <p>In the constructor, a ShapeDrawable is defines as an {@link |
| android.graphics.drawable.shapes.OvalShape}. |
| It's then given a color and the bounds of the shape are set. If you do not set the bounds, |
| then the |
| shape will not be drawn, whereas if you don't set the color, it will default to black.</p> |
| <p>With the custom View defined, it can be drawn any way you like. With the sample above, we can |
| draw the shape programmatically in an Activity:</p> |
| <pre> |
| CustomDrawableView mCustomDrawableView; |
| |
| protected void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| mCustomDrawableView = new CustomDrawableView(this); |
| |
| setContentView(mCustomDrawableView); |
| } |
| </pre> |
| |
| <p>If you'd like to draw this custom drawable from the XML layout instead of from the Activity, |
| then the CustomDrawable class must override the {@link |
| android.view.View#View(android.content.Context, android.util.AttributeSet) View(Context, |
| AttributeSet)} constructor, which is called when |
| instantiating a View via inflation from XML. Then add a CustomDrawable element to the XML, |
| like so:</p> |
| <pre> |
| <com.example.shapedrawable.CustomDrawableView |
| android:layout_width="fill_parent" |
| android:layout_height="wrap_content" |
| /> |
| </pre> |
| |
| <p>The ShapeDrawable class (like many other Drawable types in the {@link |
| android.graphics.drawable} package) |
| allows you to define various properties of the drawable with public methods. |
| Some properties you might want to adjust include |
| alpha transparency, color filter, dither, opacity and color.</p> |
| |
| <p>You can also define primitive drawable shapes using XML. For more information, see the |
| section about Shape Drawables in the <a |
| |
| href="{@docRoot}guide/topics/resources/drawable-resource.html#Shape">Drawable Resources</a> |
| document.</p> |
| |
| <!-- TODO |
| <h2 id="state-list">StateListDrawable</h2> |
| |
| <p>A StateListDrawable is an extension of the DrawableContainer class, making it little |
| different. |
| The primary distinction is that the |
| StateListDrawable manages a collection of images for the Drawable, instead of just one. |
| This means that it can switch the image when you want, without switching objects. However, |
| the |
| intention of the StateListDrawable is to automatically change the image used based on the |
| state |
| of the object it's attached to. |
| --> |
| |
| <h2 id="nine-patch">Nine-patch</h2> |
| |
| <p> |
| A {@link android.graphics.drawable.NinePatchDrawable} graphic is a |
| stretchable bitmap image, which Android will automatically resize to |
| accommodate the contents of the View in which you have placed it as the |
| background. An example use of a NinePatch is the backgrounds used by |
| standard Android buttons — buttons must stretch to accommodate strings of |
| various lengths. A NinePatch drawable is a standard PNG image that includes |
| an extra 1-pixel-wide border. It must be saved with the extension |
| <code>.9.png</code>, and saved into the <code>res/drawable/</code> directory |
| of your project. |
| </p> |
| |
| <p> |
| The border is used to define the stretchable and static areas of the image. |
| You indicate a stretchable section by drawing one (or more) 1-pixel-wide |
| black line(s) in the left and top part of the border (the other border |
| pixels should be fully transparent or white). You can have as many |
| stretchable sections as you want: their relative size stays the same, so the |
| largest sections always remain the largest. |
| </p> |
| |
| <p> |
| You can also define an optional drawable section of the image (effectively, |
| the padding lines) by drawing a line on the right and bottom lines. If a |
| View object sets the NinePatch as its background and then specifies the |
| View's text, it will stretch itself so that all the text fits inside only |
| the area designated by the right and bottom lines (if included). If the |
| padding lines are not included, Android uses the left and top lines to |
| define this drawable area. |
| </p> |
| |
| <p> |
| To clarify the difference between the different lines, the left and top |
| lines define which pixels of the image are allowed to be replicated in order |
| to stretch the image. The bottom and right lines define the relative area |
| within the image that the contents of the View are allowed to lie within. |
| </p> |
| |
| <p> |
| Here is a sample NinePatch file used to define a button: |
| </p> |
| <img src="{@docRoot}images/ninepatch_raw.png" alt=""> |
| <p> |
| This NinePatch defines one stretchable area with the left and top lines and |
| the drawable area with the bottom and right lines. In the top image, the |
| dotted grey lines identify the regions of the image that will be replicated |
| in order to stretch the image. The pink rectangle in the bottom image |
| identifies the region in which the contents of the View are allowed. If the |
| contents don't fit in this region, then the image will be stretched so that |
| they do. |
| </p> |
| |
| <p> |
| The <a href="{@docRoot}tools/help/draw9patch.html">Draw 9-patch</a> tool |
| offers an extremely handy way to create your NinePatch images, using a |
| WYSIWYG graphics editor. It even raises warnings if the region you've |
| defined for the stretchable area is at risk of producing drawing artifacts |
| as a result of the pixel replication. |
| </p> |
| |
| <h3>Example XML</h3> |
| |
| <p>Here's some sample layout XML that demonstrates how to add a NinePatch image to a |
| couple of buttons. (The NinePatch image is saved as |
| <code>res/drawable/my_button_background.9.png</code> |
| <pre> |
| <Button id="@+id/tiny" |
| android:layout_width="wrap_content" |
| android:layout_height="wrap_content" |
| android:layout_alignParentTop="true" |
| android:layout_centerInParent="true" |
| android:text="Tiny" |
| android:textSize="8sp" |
| android:background="@drawable/my_button_background"/> |
| |
| <Button id="@+id/big" |
| android:layout_width="wrap_content" |
| android:layout_height="wrap_content" |
| android:layout_alignParentBottom="true" |
| android:layout_centerInParent="true" |
| android:text="Biiiiiiig text!" |
| android:textSize="30sp" |
| android:background="@drawable/my_button_background"/> |
| </pre> |
| <p>Note that the width and height are set to "wrap_content" to make the button fit neatly around the |
| text. |
| </p> |
| |
| <p>Below are the two buttons rendered from the XML and NinePatch image shown above. |
| Notice how the width and height of the button varies with the text, and the background image |
| stretches to accommodate it. |
| </p> |
| |
| <img src="{@docRoot}images/ninepatch_examples.png" alt=""/> |
| |
| <h2 id="vector-drawable"> |
| Vector Drawables |
| </h2> |
| |
| <p> |
| A {@link android.graphics.drawable.VectorDrawable} graphic replaces multiple |
| PNG assets with a single vector graphic. The vector graphic is defined in an |
| XML file as a set of points, lines, and curves along with its associated |
| color information. |
| </p> |
| |
| <p> |
| The major advantage of using a vector graphic is image scalability. Using |
| vector graphics resizes the same file for different screen densities without |
| loss of image quality. This results in smaller APK files and less developer |
| maintenance. You can also use vector images for animation by using multiple |
| XML files instead of multiple images for each display resolution. |
| </p> |
| |
| <p> |
| Let's go through an example to understand the benefits. An image of size 100 |
| x 100 dp may render good quality on a smaller display resolution. On larger |
| devices, the app might want to use a 400 x 400 dp version of the image. |
| Normally, developers create multiple versions of an asset to cater to |
| different screen densities. This approach consumes more development efforts, |
| and results in a larger APK, which takes more space on the device. |
| </p> |
| |
| <p> |
| As of Android 5.0 (API level 21), there are two classes that support vector |
| graphics as a drawable resource: {@link |
| android.graphics.drawable.VectorDrawable} and {@link |
| android.graphics.drawable.AnimatedVectorDrawable}. For more information |
| about using the VectorDrawable and the AnimatedVectorDrawable classes, read |
| the <a href="#vector-drawable-class">About VectorDrawable class</a> and |
| <a href="#animated-vector-drawable-class">About AnimatedVectorDrawable |
| class</a> sections. |
| </p> |
| |
| <h3 id="vector-drawable-class">About VectorDrawable class</h3> |
| <p> |
| {@link android.graphics.drawable.VectorDrawable} defines a static drawable |
| object. Similar to the SVG format, each vector graphic is defined as a tree |
| hierachy, which is made up of <code>path</code> and <code>group</code> objects. |
| Each <code>path</code> contains the geometry of the object's outline and |
| <code>group</code> contains details for transformation. All paths are drawn |
| in the same order as they appear in the XML file. |
| </p> |
| |
| <img src="{@docRoot}images/guide/topics/graphics/vectorpath.png" alt=""/> |
| <p class="img-caption"> |
| <strong>Figure 1.</strong> Sample hierarchy of a vector drawable asset |
| </p> |
| |
| |
| <p> |
| The <a href="{@docRoot}studio/write/vector-asset-studio.html">Vector Asset |
| Studio</a> tool offers a simple way to add a vector graphic to the project |
| as an XML file. |
| </p> |
| |
| <h4> |
| Example XML |
| </h4> |
| |
| <p> |
| Here is a sample <code>VectorDrawable</code> XML file that renders an image |
| of a battery in the charging mode. |
| </p> |
| |
| <pre> |
| <!-- res/drawable/battery_charging.xml --> |
| <vector xmlns:android="http://schemas.android.com/apk/res/android" |
| <!-- intrinsic size of the drawable --> |
| android:height="24dp" |
| android:width="24dp" |
| <!-- size of the virtual canvas --> |
| android:viewportWidth="24.0" |
| android:viewportHeight="24.0"> |
| <group |
| android:name="rotationGroup" |
| android:pivotX="10.0" |
| android:pivotY="10.0" |
| android:rotation="15.0" > |
| <path |
| android:name="vect" |
| android:fillColor="#FF000000" |
| android:pathData="M15.67,4H14V2h-4v2H8.33C7.6,4 7,4.6 7,5.33V9h4.93L13,7v2h4V5.33C17,4.6 16.4,4 15.67,4z" |
| android:fillAlpha=".3"/> |
| <path |
| android:name="draw" |
| android:fillColor="#FF000000" |
| android:pathData="M13,12.5h2L11,20v-5.5H9L11.93,9H7v11.67C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33V9h-4v3.5z"/> |
| </group> |
| </vector> |
| </pre> |
| |
| <p>This XML renders the following image: |
| </p> |
| |
| <img src= |
| "{@docRoot}images/guide/topics/graphics/ic_battery_charging_80_black_24dp.png" |
| alt=""/> |
| |
| <h3 id="animated-vector-drawable-class"> |
| About AnimatedVectorDrawable class |
| </h3> |
| |
| <p> |
| {@link android.graphics.drawable.AnimatedVectorDrawable |
| AnimatedVectorDrawable} adds animation to the properties of a vector |
| graphic. You can define an animated vector graphic as three separate |
| resource files or as a single XML file defining the entire drawable. Let's |
| look at both the approaches for better understanding: <a href= |
| "#multiple-files">Multiple XML files</a> and <a href="#single-file">Single |
| XML file</a>. |
| </p> |
| |
| <h4 id="multiple-files"> |
| Multiple XML files |
| </h4> |
| <p> |
| By using this approach, you can define three separate XML files: |
| |
| <ul> |
| <li>A {@link android.graphics.drawable.VectorDrawable} XML file. |
| </li> |
| |
| <li> |
| An {@link android.graphics.drawable.AnimatedVectorDrawable} XML file that |
| defines the target {@link android.graphics.drawable.VectorDrawable}, the |
| target paths and groups to animate, the properties, and the animations defined |
| as {@link android.animation.ObjectAnimator ObjectAnimator} objects or {@link |
| android.animation.AnimatorSet AnimatorSet} objects. |
| </li> |
| |
| <li>An animator XML file. |
| </li> |
| </ul> |
| </p> |
| |
| <h5> |
| Example of multiple XML files |
| </h5> |
| <p> |
| The following XML files demonstrate the animation of a vector graphic. |
| |
| <ul> |
| <li>VectorDrawable's XML file: <code>vd.xml</code> |
| </li> |
| |
| <li style="list-style: none; display: inline"> |
| <pre> |
| <vector xmlns:android="http://schemas.android.com/apk/res/android" |
| android:height="64dp" |
| android:width="64dp" |
| android:viewportHeight="600" |
| android:viewportWidth="600" > |
| <group |
| android:name="rotationGroup" |
| android:pivotX="300.0" |
| android:pivotY="300.0" |
| android:rotation="45.0" > |
| <path |
| android:name="vectorPath" |
| android:fillColor="#000000" |
| android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> |
| </group> |
| </vector> |
| </pre> |
| </li> |
| |
| <li>AnimatedVectorDrawable's XML file: <code>avd.xml</code> |
| </li> |
| |
| <li style="list-style: none; display: inline"> |
| <pre> |
| <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" |
| android:drawable="@drawable/vd" > |
| <target |
| android:name="rotationGroup" |
| android:animation="@anim/rotation" /> |
| <target |
| android:name="vectorPath" |
| android:animation="@anim/path_morph" /> |
| </animated-vector> |
| </pre> |
| </li> |
| |
| <li>Animator XML files that are used in the AnimatedVectorDrawable's XML |
| file: <code>rotation.xml</code> and <code>path_morph.xml</code> |
| </li> |
| |
| <li style="list-style: none; display: inline"> |
| <pre> |
| <objectAnimator |
| android:duration="6000" |
| android:propertyName="rotation" |
| android:valueFrom="0" |
| android:valueTo="360" /> |
| </pre> |
| |
| <pre> |
| <set xmlns:android="http://schemas.android.com/apk/res/android"> |
| <objectAnimator |
| android:duration="3000" |
| android:propertyName="pathData" |
| android:valueFrom="M300,70 l 0,-70 70,70 0,0 -70,70z" |
| android:valueTo="M300,70 l 0,-70 70,0 0,140 -70,0 z" |
| android:valueType="pathType"/> |
| </set> |
| </pre> |
| </li> |
| </ul> |
| </p> |
| <h4 id="single-file"> |
| Single XML file |
| </h4> |
| |
| <p> |
| By using this approach, you can merge the related XML files into a single |
| XML file through the XML Bundle Format. At the time of building the app, the |
| <code>aapt</code> tag creates separate resources and references them in the |
| animated vector. This approach requires Build Tools 24 or higher, and the |
| output is backward compatible. |
| </p> |
| |
| <h5> |
| Example of a single XML file |
| </h5> |
| <pre> |
| <animated-vector |
| xmlns:android="http://schemas.android.com/apk/res/android" |
| xmlns:aapt="http://schemas.android.com/aapt"> |
| <aapt:attr name="android:drawable"> |
| <vector |
| android:width="24dp" |
| android:height="24dp" |
| android:viewportWidth="24" |
| android:viewportHeight="24"> |
| <path |
| android:name="root" |
| android:strokeWidth="2" |
| android:strokeLineCap="square" |
| android:strokeColor="?android:colorControlNormal" |
| android:pathData="M4.8,13.4 L9,17.6 M10.4,16.2 L19.6,7" /> |
| </vector> |
| </aapt:attr> |
| <target android:name="root"> |
| <aapt:attr name="android:animation"> |
| <objectAnimator |
| android:propertyName="pathData" |
| android:valueFrom="M4.8,13.4 L9,17.6 M10.4,16.2 L19.6,7" |
| android:valueTo="M6.4,6.4 L17.6,17.6 M6.4,17.6 L17.6,6.4" |
| android:duration="300" |
| android:interpolator="@android:interpolator/fast_out_slow_in" |
| android:valueType="pathType" /> |
| </aapt:attr> |
| </target> |
| </animated-vector> |
| </pre> |