Animated vectors are growing in popularity, but technical expertise and learning resources for the feature remain limited within the Android community. The documentation contains surprisingly little practical information and assumes a lot of preexisting knowledge of SVGs. I’ve been disappointed to see this overlooked at conferences as well, but hope that the in-depth knowledge I’ve acquired through my own trial and error will assist other developers in creating their own awesome animations.
This is a talk about Shapeshifting - creating delightful icon animations. My name is Or Bar, and I work at Tumblr.
When I graduated from university and I was trying to teach myself android, Jellybean was the new thing. I was trying to wrap my head around the fragment lifecycle, and more advanced apps and more experienced developers started introducing new navigation drawers and new elements that were not in the framework.
Next, Google Apps introduced their own navigation drawers and they had various different implementations. I wanted to know how this was done. I opened the Action Bar Drawer Toggle and I looked at the code and found that the code figured out where in the animation you are, and it drew it on the canvas. I closed the file and I figured I’ll never have the time to implement something like this.
When Timely, a clock app, came out, it had many animations. There are numbers that morphed, lines that changed size and color, bubbles that moved for no apparent reason.
I Googled around and I found this great article about number tweening. It explained how the numbers are not fonts, but rather they are past a being drawn directly to the canvas. There are control points; it was very interesting but ultimately it was very complex.
Get more development news like this
I realized that icons are more than just icons, they convey information and make the experience a good one.
Building Animations with SVG
SVG or the Scalable Vector Graphic is an image file format that’s optimized for a small file size - this results in smaller files than the equivalent png or jpeg. SVGs are also scalable, meaning that single SVG file won’t lose quality as you display it on a larger screen.
This is an SVG file - it has an SVG element with some attributes.
<?xml version="1.0" encoding="UTF-8"?> <svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http:// www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch --> <title>btn_bold</title> <desc>Created with Sketch.</desc> <defs></defs> <g id="_Assets" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="btn_bold" fill-rule="nonzero" fill="#8F8F8F"> <path d=“M30.156,27.644 … Z” id="B"></path> </g> </g> </svg>
The SVG format uses a basic cartesian coordinate system with the top left corner as (0,0). It also supports transformations, some of them as simple as rotation scale and translation but also as complex as shearing.
The viewbox attribute, which defines the user space that will stretch to the bounds of your final container.
For example, you can define given whatever size you can define a viewbox that’s four pixels by four pixels or four by four; viewBox=”0 0 4 4”, this is how you define a grid. To actually draw, SVG has different options. One of the most important and useful ones is Path.
Path represents the outline of the shape you want to draw. A path can be filled, stroked, or used to clip other paths in the same image. The ‘d’ attribute, which is also known as the Path Data, is a string of letters and numbers that represent commands for the computer to follow when drawing the shape.
The path data typically dominates the SVG file, it’s usually the longest, and therefore it’s compressed as much as possible. Commands are one letter long, white spaces and commas are omitted whenever possible.
A path also contains multiple segments which are useful when you want to compress the file even smaller. There is a fill and a stroke attribute which are used to set the colors of the shape. The fill rule is used to determine how you fill the shape.
Path Data - moveto
Instructions always start with a letter followed by zero or more parameters. Instructions can either be lower case or upper case. The difference being that uppercase instructions use absolute coordinates while lower case means relative coordinates.
Path Data - lineto
The next command is the
lineto command, which is a simple instruction to draw a line.
There are two variants to this command. One for drawing horizontal lines, one for vertical, so you can stay if one character.
Path Data - curveto
The next command is the
curveto, which draws a bezier curve from the current point to (x,y) using x1 y1 one as the control point at the beginning of the curve and x2 y2 as the control point at the end of the curve. The ‘S’ instruction is shorthand, and for the ‘C’, the curve instruction where the first control point is assumed to be a mirror of the second control point. There’s also ‘Q’ and ‘T’ commands that are used to draw quadratic bezier curves and an ‘A’ command is used to draw elliptical arcs.
Path Data - closepath
closepath draws a straight line from the current position to the start position of the path.
Path - Stroke
stroke command defines the color of the path while the stroke width defines the width of the path.
Path - Fill
fill attribute describes the color used to fill the shape that the path is describing. The fill rule describes the strategy used to fill the shape.
VectorDrawables are the Android version of the SVG format. It’s very small but powerful subset of the SVG spec. Its syntax should be familiar for Android developers.
Vectordrawables also use the coordinate system. The properties are
viewportheight which are equivalent to SVGs viewbox property; however, you only specify the width and height.
There is width and height, which are the intrinsic width and height of the drawable and that’s used to generate pngs for supporting pre-lollipop devices.
The path elements is Android’s version of the SVG path; these are very similar to SVG. Path data is the same as the ‘d’ attribute, fill color, strokecolor and strokewidth are all very self-explanatory.
This is what a vectordrawable looks like.
<vector android:width=“24dp” android:height=“24dp” android:viewportHeight=“24.0” android:viewportWidth=“24.0”> <path android:name=“circle” android:fillColor=“#33d4db” android:pathData=“M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0” /> <path android:name=“tick” android:pathData=“M6,11 l3.5,4 l8,-7” android:strokeColor=“#ff3b80” android:strokeWidth=“#1” /> </vector>
This draws a circle with a check mark in the center. The top-level element is the vector and it has the width, height, and the viewport width and height and then inside the vector element, we have two path elements. The path has a name attribute and that becomes useful when you want to animate the path but it’s also useful because it’s not obvious from the path data what it’s drawing. Also, the order of the path does matter for the ‘z’ index, the final ‘z’ index of the path. In this case, the check mark is drawn on top of the circle and not vice versa.
Android Studio has a handy tool to create vectordrawable, which allows you to pick from hundreds of material style icons.
If you get an SVG from a designer, and you import it through Android Studio, you may be left confused by why the SVG has a hole in the middle, but the vector drawable does not.
The problem is the strategy used to fill the shape. SVG is using something called the even-odd rule, and Android only started supporting that in API 24. A solution to this is to use minSdk 24, targeting 95% of the users in the room.
Some other solutions are to:
Convert the even-oddfill to a non-zero fill which is the rule that android supports. We draw a ray and count how many times that ray crosses a path, and if the path crosses from the left side to the right side we increase the count by one and if it crosses from the left to the right, we decrease by one.
Use the Support library (version 25.4 or newer) for the even-odd rule, as backporting
animatedvectordrawablesgoes back to ice cream sandwich.
animatedvectordrawables allow you to take vectordrawables and make them animatable. You can assign each element or each path or a group of paths a unique name and then the animatedvectordrawable can map that to objectanimators.
An animatedvectordrawable looks like a simple xml resource file that you place inside your drawable directory.
<animated-vector android:drawable=“@drawable/bug_droid" > <target android:name=“right_arm” android:animation=“@anim/wave" /> </animated-vector>
You start with an animatedvector object and you pass that your vectordrawable resource. This will be used as the start state of the animation, then you give it one or more mappings from a path or a group to an animation.
Transformations are animations you apply to a group of one or more paths and you animate them as a unit without completely changing the shape of the path.
Suppose you start with a simple arrow that you want to flip. You can break the two parts of the arrow into two separate paths and then you can animate them separately at the same time.
In this animation, we rotate around the center point and we transform with delay back into where it’s supposed to end up.
Trimming Stroked Paths
Another very powerful property of paths is the ability to trim them before they appear on the display before they are drawn. This gives you the ability to create some nice effects so you can trim the path either at the start, at the end and you can also offset the trim position.
With a simple line, you can trim the first 20 percent, last 20 percent, and also offset the whole thing. By animating these three properties you can make nice effects, such as even recreating Material design progress bars.
Path morphing is the coolest and most powerful animation that you can do with animatedvectordrawables, but it’s also one of the hardest ones to implement.
That first path and second path must have the same number of commands. The nth drawing command in the first path must have the same type as the nth drawing command in the second path for all ‘n’, where ‘n’ means that the nth drawing command.
Path clipping or a path clip is a type of path that’s used to mask or restrict a region to which other paths can be drawn to. Anything that lies outside the region bounded by a clip path will not be drawn to the screen. By animating the bridge of these regions, you can create some cool effects like an eye with a slash going through it.
About the content
This talk was delivered live in July 2017 at 360 AnDev. The video was recorded, produced, and transcribed by Realm, and is published here with the permission of the conference organizers.