Vector graphics in android

Android Vector Drawables

There are two basic ways an image can be represented in: Bitmaps and Vector Drawables. Normal Bitmaps are represented in the form of pixels in a grid. A Vector Drawable defines the image in the form of geometry, i.e as a set of points in the cartesian plane, connected through lines and curves, with their associated color information.

In this post we’ll be focuss
Android Vector Drawables

There are two basic ways an image can be represented in: Bitmaps and Vector Drawables. Normal Bitmaps are represented in the form of pixels…

Note: Changes here will affect how your story appears in public places like Medium’s homepage — not the story itself.

Add or change tags (up to 5) so readers know what your story is about

Android×
Add a tag…

Allow curators to recommend my story to interested readers.ing on static Vector Drawables and some of their advanced features. Animated Vector Drawables will be covered very briefly.

Why Vector Drawables?

Vector Drawables are,

All Bitmaps have a specific resolution, which when displayed on a different density display may pixelate or might introduce unwanted artifacts. Vector Drawables look sharp on each display independent of display density, i.e. the same file is resized for different screen densities.

A Bitmap of higher resolution means more pixels. More pixels means larger file size. Vector Drawables do not store pixels therefore they are of the same size independent of display density. This results in smaller APK files and less developer maintenance.

Vector Drawables are highly flexible. One can also animate them using multiple XML files.

The support for Vector Drawables was added in API Level 21(Lollipop). Prior to this release if anyone wanted to represent images through Vector Graphics they had to do it manually though Java Code. If Bitmaps were used, developers had to use different images, one for each display resolution. Imagine using animated Bitmaps in such a situation!

There are two classes that help you use Vector Drawables: VectorDrawable and AnimatedVectorDrawable.

The VectorDrawable Class

This class defines a static drawable object. It is defined in a manner similar to the SVG format.

It follows a tree hierarchy consisting of groups and paths. The path contains the actual geometric data to draw the object. The group contains data for transformation of the shape. The path is always a leaf of the tree. The path will be joined in same order in which it appears in the file.

The group text is an internal node of the tree. A path object inherits all the transformation of it’s ancestor groups.

Let’s take a look at a sample Vector Graphic as an SVG file and its corresponding XML Vector Drawable.

android:fillColor=”#000000″
android:fillAlpha=”.3″
android:pathData=”M15.67 4H14V2h-4v2H8.33C7.6 4 7 4.6 7 5.33V8h5.47L13 7v1h4V5.33C17 4.6 16.4 4 15.67 4z”/>

android:fillColor=”#000000″
android:pathData=”M13 12.5h2L11 20v-5.5H9L12.47 8H7v12.67C7 21.4 7.6 22 8.33 22h7.33c0.74 0 1.34–0.6 1.34–1.33V8h-4v4.5z”/>

This Vector Drawable renders an image of a battery in charging mode.

There’s a lot more you can do with Vector Drawables. For example you can specify the tint for the image. You needn’t worry if the SVG the designer gave has the right shade of grey you need. The same Vector Drawable renders with different colors according to the set theme.

All you need to do to set the tint is add this attribute to the vector:

You can also use theme colors for specific parts of your image. For example in order to use colorPrimary in you image add this attribute to your path:

Many a times we need to change the color of icons depending on the state of the button. These changes might be as minor as a different colored stroke. You can accomplish this using different colored images, but when the rendering is the same for most of the part, using ColorStateList inside the Vector Drawable is a much better way. You can avoid a lot of duplication in this manner.

The way to accomplish this is the same as that of a regular ColorStateList. Create a ColorStateList in the color resource directory, and use a reference to it in the fillColor attribute in the path.

If your ColorStateList is csl_image.xml, the add this line:

Vectors also support gradients. You can have three types of gradients:

We can also define individual color stops using tag to get more fine grained gradients as show below:

This sets the color at 72% of the gradient direction parameter.

Читайте также:  Grand theft auto android skachat

Just as we define ColorStateLists in the color resource directory, we can define gradients and then add their reference in our Vector Drawable in the fillColor attribute.

An alternative to this is to define the gradient using inline resource syntax to embed it inside the vector definition itself as shown below.

Here the AAPT(Android Asset Packaging Tool) will extract this to a color resource at build time and insert a reference for it.Gradients are very useful in situations where you need shadows in Vector Drawables. Vector don’t support shadows, but it can be faked using gradients. You can also use it to create customized spinners using a radial gradient.

If the gradient doesn’t fill the entire image, you may choose to so any of the following:

This is the default mode. It just continues the color outwards from the last offset point

You may accomplish this by adding the following line in the gradient:

This repeats the gradient until the whole image is filled.

You may accomplish this by adding the following line in the gradient:

This goes back and forth through the gradient.

You may accomplish this by adding the following line in the gradient:

We can also make gradients that do not go from color to color but have regions of solid color.

This can be accomplished by using the same color between two color stops, as shown below:

The AnimatedVectorDrawable Class

This class adds animation to the properties of a VectorDrawable. We can define animated vector drawables in two ways:

A VectorDrawable file, an AnimatedVectorDrawable file and an animator XML file.

  • Using a single XML file
  • You can also merge related XML files using XML Bundle Format.

To support vector drawable and animated vector drawable on devices running platform versions lower than Android 5.0 (API level 21), VectorDrawableCompat and AnimatedVectorDrawableCompat are available through two support libraries: support-vector-drawable and animated-vector-drawable, respectively.

Support Library 25.4.0 and higher supports the following features:

  • Path Morphing (PathType evaluator) Used to morph one path into another path.
  • Path Interpolation Used to define a flexible interpolator (represented as a path) instead of the system-defined interpolators like LinearInterpolator.

Support Library 26.0.0-beta1 and higher supports the following features:

  • Move along path The geometry object can move around, along an arbitrary path, as part of an animation.

For more information about Animated Vector Drawables you can refer to the links posted at the end of the post.

Performance tradeoff for Vector Drawables

Although the XML file used for Vector Drawables is usually smaller than conventional PNG images, it has significant computational overhead at runtime in case the drawn object is complex. When the image is rendered for the first time, a Bitmap cache is created to optimize redrawing performance. Whenever the image needs to be redrawn, the same Bitmap cache is used unless the image size is changed. So, for example you rotate your device, if the size of the rendered image remains the same, it will be rendered using the same cach otherwise the cache will be rebuilt. Therefore in comparison to raster images they take longer to render for the first time.

As the time taken to draw them is longer, Google recommends a maximum size of 200 x 200 dp.

Источник

Understanding Android’s vector image format: VectorDrawable

Android devices come in all sizes, shapes and screen densities. That’s why I’m a huge fan of using resolution independent, vector assets. But what exactly are they? What are their benefits? What are the costs? When should I use them? How do you create and use them? In this series of posts I’d like to explore these questions and explain why I think that the vast majority of the assets in your apps should be vectors, and how to get the most out of them.

Raster vs Vector

Most image formats (png, jpeg, bmp, gif, webp etc) are raster which means they describe the image as a fixed grid of pixels. As such they’re defined at a particular resolution and don’t understand anything about their contents, just the color of each pixel. Vector graphics however describe the image as a series of shapes defined over an abstract canvas size.

Why vector?

Vector assets have 3 main benefits, they are:

Sharp

Vector images resize gracefully; because they describe the image over an abstract canvas size you can scale this canvas up or down and then redraw the image at that size. Raster assets however can deteriorate when you resize them. Scaling raster assets down tends to be ok (as you’re discarding information) but scaling them up leads to artifacts like fuzziness or banding, because they have to interpolate the missing pixels.

Читайте также:  Как получить координаты маркера google maps android

This is why on Android we need to provide multiple versions of each raster asset for different density screens:

  • res/drawable-mdpi/foo.png
  • res/drawable-hdpi/foo.png
  • res/drawable-xhdpi/foo.png

Android picks the closest larger density and scales it down (if needed). With the trend for devices with ever higher density screens, app makers must keep creating, including and shipping ever larger versions of the same assets. Note that many modern devices don’t sit on exact density buckets (e.g. the Pixel 3 XL is 552dpi, somewhere between xxhdpi & xxxhdpi) so assets will often be scaled.

Because vector assets resize gracefully, you can include a single asset, safe in the knowledge that it will work on any and all screen densities.

Small

Vector assets are generally* more compact than raster assets both because you only need to include a single version, and because they compresses well.

For example here’s a change from the Google I/O app where we switched a number of icons from raster PNGs to vectors and saved 482KB. While this might not sound like much, this was just for small iconography; larger images (such as illustrations) would have larger savings.

This illustration for example from the on-boarding flow of a previous year’s I/O app for example:

We could not replace this with a VectorDrawable as gradients were not supported widely at that time (spoiler: they are now!) so we had to ship a raster version 😔. If we had been able to use a vector, this would have been 30% the size for a better result:

  • Raster: Download Size = 53.9KB (Raw file size = 54.8KB)
  • Vector: Download Size = 3.7KB (Raw file size = 15.8KB)

Note that while Android App Bundle’s density configuration splits bring similar benefits by only delivering the required density assets to the device, a VectorDrawable will generally still be smaller and also removes the need to keep creating ever larger raster assets.

Dynamic

As vector images describe their contents rather than ‘flattening’ them down to pixels, they open the door to interesting new possibilities like animation, interactivity or dynamic theming. More on this in future posts.

Trade-offs

Vectors do have some drawbacks that need to be considered:

Decoding

As previously stated, vector assets describe their contents, therefore they need to be inflated and drawn before use.

There are two steps to this:

  1. Inflation. Your vector file has to be read and parsed into a VectorDrawable modeling the the paths, groups etc you declare.
  2. Drawing. These model objects then have to be drawn by executing Canvas drawing commands.

Both of these steps are proportional to the complexity of the vector and the type of operations you perform. If you use very intricate shapes, it will take longer to parse this into a Path . Similarly, more drawing operations will take longer to perform (and some are more expensive e.g. clip operations). We’ll revisit this in a future post in this series on profiling these costs.

For static vectors, the drawing stage only needs to be performed once and can then be cached to a Bitmap . Animated vectors, can’t make this optimization as their properties necessarily change requiring re-drawing.

Compare this to raster assets like PNGs which only need to decode the file’s contents, something which has been highly optimized over time.

This is the essential tradeoff of raster vs vector. Vectors provide the aforementioned benefits but at the cost of being more expensive to render. In Android’s early days, devices were less powerful and screen densities differed little. Today, Android devices are more powerful and come in a huge variety of screen densities. This is why I believe it is time for all apps to move to vector assets.

Suitability

Due to the nature of the format, vectors are great at describing some assets like simple icons etc. They’re terrible at encoding photographic type images where it’s harder to describe their contents as a series of shapes and it would likely be a lot more efficient to use a raster format (like webp). This is of course a spectrum, depending upon the complexity of your asset.

Conversion

No design tooling (that I know of) creates VectorDrawable s directly which means that there is a conversion step from other formats. This can complicate the workflow between designers and developers. We’ll go into this topic in depth in a future post.

Why not SVG?

If you’ve ever worked with vector image formats, you’ll likely have come across the SVG format (Scalable Vector Graphics), the industry standard on the web. It is capable and mature with established tooling, but it’s also a vast standard. It includes many complex capabilities like executing arbitrary javascript, blur and filter effects or embedding other images, even animated gifs. Android runs on constrained mobile devices so supporting the entirety of the SVG spec wasn’t a realistic goal.

Читайте также:  Android create background service

SVG does however include a path spec which defines how to describe and draw shapes. With this API you can express most vector shapes. This is essentially what Android supports: SVG’s path spec (plus a few additions).

Additionally, by defining its own format, VectorDrawable can integrate with Android platform features. For example working with the Android resource system to reference @colors , @dimens or @strings , working with theme attributes or AnimatedVectorDrawable using standard Animator s.

VectorDrawable ’s Capabilities

As stated, VectorDrawable supports SVGs path spec, allowing you to specify one or many shapes to be drawn. It’s authored as an XML document which looks like this:

Note that you need to specify the asset’s intrinsic size, which is the size it would be if you set it in a wrap_content ImageView . The second viewport sizes define the virtual canvas, or coordinate space all subsequent drawing commands are defined in. The intrinsic and viewport dimensions can differ (but should be in the same ratio)—you could define your vectors in a 1*1 canvas if you really want.

The element contains one or many

elements. They can be named (for later reference e.g. animation) but crucially must specify a pathData element which describes the shape. This cryptic looking string can be thought of as a series of commands controlling a pen on a virtual canvas:

The above commands move the virtual pen, then draw a line to another point, lift and move the pen, then draw another line. With just the 4 most common commands we can describe pretty much any shape (there are more commands see the spec):

  • M move to
  • L line to
  • C (cubic bezier) curve to
  • Z close (line to first point)

(Upper case commands use absolute coordinates & lowercase use relative)

You might wonder if you need to care about this level of detail — don’t you just get these from SVG files? While you don’t need to be able to read a path and understand what it will draw, having a basic understanding of what a VectorDrawable is doing is extremely helpful and necessary for understanding some of the advanced features we’ll get to later.

Paths by themselves don’t draw anything, they need to be stroked and/or filled.

Part 2 of this series goes into more detail on the different ways of filling/stroking paths.

You can also define groups of paths. This allows you to define transformations that will be applied to all paths within the group.

Note that you can’t rotate/scale/translate individual paths. If you want this behavior you’ll need to place them in a group. These transformation make little sense for static images which could ‘bake’ them into their paths directly — but they are extremely useful for animating.

You can also define clip-path s, that is mask the area that other paths in the same group can draw to. They’re defined exactly the same way as path s.

One limitation of note is that clip-paths are not anti-aliased.

This example (which I’ve had to enlarge greatly to show the effect) shows two approaches for drawing a camera shutter icon. The first draws the paths, the second draws a solid square, masked to the shutter shape. Masking can help to create interesting effects (especially when animated) but it’s relatively expensive so if you can avoid it by drawing a shape in a different way, then do.

Paths can be trimmed; that is only draw a subset of the entire path. You can trim filled paths but the results can be surprising! It’s more common to trim stroked paths.

You can trim either from the start, or end of a path or apply an offset to any trims. They are defined as a fraction of the path [0,1]. See how setting different trim values changes the portion of the line that is drawn. Also note that offsets can make the trim values ‘wrap around’. Once again, this property doesn’t make much sense for static images but is handy for animation.

The root vector element supports an alpha property [0, 1]. Groups do not have an alpha property but individual paths support fillAlpha / strokeAlpha .

Declare Independence

So hopefully this post gives you an idea of what vector assets are, their benefits and trade-offs. Android’s vector format is capable and has widespread support. Given the variety of devices in the market, using vector assets should be your default choice, only resorting to rasters in special cases. Join us in the next posts to learn more:

Источник

Оцените статью