VectorDrawable

VectorDrawables – Part 1

One of the really exciting new features in Lollipop is the inclusion of VectorDrawable and some associated classes which provide some extremely powerful new options for adding complex vector graphics as paths (which will scale across form-factors, screen sizes, and densities much better than bitmaps), and provide some equally powerful tools to animate them. In this series we’ll take a look at them and look at some of the advantages they give us, and looks at how we can get some really impressive results from relatively small amounts of code.

First things first: a small explanation. When Styling Android first started in February 2011 the inaugural post was entitled Vector Drawables, and there has subsequently been a follow up series to this. These actually covered Shape Drawables and have since been renamed accordingly. However, I felt a brief explanation was necessary for anyone with feeling of déjà vu – this really is covering a different subject than those earlier posts.

Simply explained, vector graphics are a way of describing graphical elements using geometric shapes. They are particularly well suited to graphical elements created in packages such as Adobe Illustrator or Inkscape where simple geometric shapes may be combined in to much more complex elements. Bitmap graphics, on the other hand, define the colour value for each pixel and are particularly well suited to photographic images. The big advantage of using vector graphics (where appropriate) is that they are rendered at run time, so will automatically be rendered at the pixel density of the device on which they are being rendered – thereby giving smooth graphics irrespective of device capabilities. They are also usually much smaller than the bitmap version of the same graphic. They do, however, come with a computational overhead at run time which may be an issue for more complex graphical elements.

In Android, they have been implemented using the new VectorDrawable class which has been introduced in Lollipop (although there is a third-party back-port of VectorDrawable named MrVector which I have not tried myself, but this library does not currently include support for AnimatedVectorDrawable which we’ll be covering later in this series, although it is on the roadmap). This means that for graphical elements which are well suited to vector representation we can replace mdpi, hdpi, xhdpi, xxhdpi, and xxxhdpi bitmap versions of a specific drawable with a single VectorDrawable which will be a fraction of the size of even the mdpi bitmap version.

To demonstrate this, let’s take the following SVG file (which I found in a library for displaying SVG graphics in Android):

android

This file is 2265 bytes as an SVG graphic, but if we render it at a bitmap of 500×500 pixels and save as a PNG it is 13272 bytes – and we’d have to use multiple bitmaps for different pixel densities whereas we only require a single vector graphic. But SVG is not the same as a VectorDrawable, so we can’t use it directly. However, VectorDrawable supports a subset of the SVG specification so we can take some elements from the SVG file and use them in our VectorDrawable. The key components which we can use are the SVG path definitions. SVG paths are analogous with the android.graphics.Path APIs but are defined as a string which we can use within our VectorDrawable. So let’s have a look at the SVG source:

While this looks pretty scary, we can lift the bit out that we need without having to understand the inner workings! There are some attributes in the parent <svg> element which define the canvas and view port sizes as being 500x500px, then there’s a <g> (group) element which defines a border which we’ll ignore. Then there is another <g> (group) element with the id “androd” (sic) which is the Android logo itself – this is the real bit that we need. It consists of 6 <path> elements which define the head; left eye; right eye; left arm; body & legs; right arm components of the image respectively. The fill attribute of each defines the fill colour (and we can see that all of these are green except for the two eyes which are both white), followed by a d attribute which contains the path data. For those wanting to understand the path data specification then please refer to the SVG Path Specification, but that’s not essential because we can simply take these path specifications as they are and use them within our VectorDrawables.

So let’s create our VectorDrawable:

We’ve created a parent <vector> element which contains the width and height specifications, then we have a <group> element which contains 6 <path> elements each containing the relevant fill and path data which we have simply copied and pasted from the SVG file. I’ve added name attributes to each of the <path> elements to make it easier to understand what each path element represents, but we’ll use these names as the series progresses. This file is still a pretty modest 2412 bytes.

We can now use this like any drawable:

…and if we run this we can see it rendering nicely:

simple_vector_drawable

On small thing worth noting: While this particular VectorDrawable renders well, I have seen some issues with some other VectorDrawables containing path data extracted from SVG files not rendering well in Android Studio (at the time of writing I’m using V1.0.2 and there is a bug report for the issue here) yet rendering perfectly on a device. So always try running on a real device if you experience problems with the Android Studio preview.

So now we can significantly reduce our APK size if we use VectorDrawables where appropriate, and this will also make apps much easier to maintain because we won’t need to add new assets when we need to support additional screen densities. However, this is not all that VectorDrawables can do for us, and in the next article we’ll look at how we can animate VectorDrawables.

The source code for this article is available here.

© 2015, Mark Allison. All rights reserved.

CC BY-NC-SA 4.0 VectorDrawables – Part 1 by Styling Android is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Permissions beyond the scope of this license may be available at http://blog.stylingandroid.com/license-information.

6 Comments

    1. There’s no simple answer it really depends on your project requirements and the nature of the images you’re using.

      If you only need static vectors then you may find that MrVector (mentioned in the article) will provide the necessary functionality for pre-Lollipop devices.

  1. This is really awesome!! But i have a doubt. Is it possible to change the color of the 6 elements(head; left eye; right eye; left arm; body & legs; right arm ) according to our input? Say for example, if i give a number which is greater than 20, the image should change to black. if i give a number which is greater than 40, the image should change to blue.

  2. Hello Mark.

    I would like to translate your articles into Russian. I will publish translated articles on the popular Russian website: http://habrahabr.ru

    I would like to start with an article VectorDrawables – Part 1-4. I recently ran into this topic and your article helped me. I would like to get your permission to use your text, code examples, and videos. In each publication, I’ll write your name and a link to the original article.

    1. hi. i have used vector drawables to render maps. i have then added pinch zoom functionality but when i zoom the maps their quality decreases significantly. is their any redraw command which we can give when the image is scaled. any help will be highly appreciated.

Leave a Reply

Your email address will not be published. Required fields are marked *