Previously in this series we’ve looked at how we can create VectorDrawables and animate path groups, and also animate the rendering of the paths. However, there is even more that we can animate by actually modifying the SVG path data itself, and in this concluding article in this series we’ll look at how we can do that.
In order to modify the SVG path data we’re actually going to have to have a little bit of a dive in the SVG path format and understand a little bit about what is going on. I’m not going to give a full SVG path tutorial as it’s already documented here. However let’s look at how we can draw a simple square:
<?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:viewportWidth="500" android:viewportHeight="500" android:width="500px" android:height="500px"> <path android:name="square" android:fillColor="@color/sa_green" android:pathData="M100,100 L400,100 L400,400 L100,400 z" /> </vector>
Most of this should be fairly familiar by now, but let’s analyse the
pathData within the path element. First let’s bear in mind that the viewport is 500 x 500 pixels, so we’re working within that co-ordinate space. There are 5 different commands within the path data (I have separated them with spaces, but the spaces are optional, and I’ve included them simply to aid readability). The first is
M100,100 which moves the current drawing position to point 100, 100 (the capital
M means that we’re specifying an absolute co-ordinate, we could use a relative position by specifying a lowercase
m instead, and this is true of all commands). This has effectively positioned the current location to the top left corner of the square which we’re drawing.
The next three commands
L400,100 L400,400 L100,400 are going to draw lines from the top left to the top right corner, the top right to the bottom right corner, and the bottom right to the bottom left corner respectively. Once again we’re specifying absolute co-ordinates here.
The final command
z simply closes the path. In other words, the current position is the bottom left corner and closing the path will draw a line from the current position back to the start position which draws the final line of our square.
This gets filled with the filled green, and the preview within Android Studio looks like this:
There’s an awful lot more that we can do in SVG paths, but a simple square will suit our purposes.
The next thing we need to do is define a really simple AnimatedVectorDrawable as we have before to assign an Animator to this path element:
<?xml version="1.0" encoding="utf-8"?> <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/square"> <target android:animation="@animator/to_triangle" android:name="square" /> </animated-vector>
Now comes the clever bit – the Animator itself. What we’re going to do is animate the square in to a triangle. We do this by defining the start and end values as two different paths. The start path will be the square that we created in the VectorDrawable, and the end path will be the triangle.
It is important to remeber that the start and end paths must have the same number of elements and these element types must match. Our squre consisten of a move command followed by 3 line commands and a closepath command, and our triangle will need to match this pattern. But surely our triangle will only require three lines when our square required four, so we’ll need to cheat a little. What we’ll do is position both of the verticies representing the two top corners in the middle of the top endge of the square (ie at position 250, 100). So they will both occupy the same space and we’ll ‘lose’ one of the edges resulting in a triangle being displayed.
android:valueType="pathType" the Animator will generate interpolated values for each of the path commands for each frame of the animation:
<?xml version="1.0" encoding="utf-8"?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:interpolator="@android:interpolator/decelerate_cubic" android:repeatMode="reverse" android:repeatCount="1" android:propertyName="pathData" android:valueType="pathType" android:valueFrom="M100,100L400,100L400,400L100,400z" android:valueTo="M250,100L250,100L400,400L100,400z" />
Let’s not leave it there though, why don’t we change the colour while we’re at it? Once again this is really simple. First we add an additional target to the AnimatedVectorDrawable:
<?xml version="1.0" encoding="utf-8"?> <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/square"> <target android:animation="@animator/to_triangle" android:name="square" /> <target android:animation="@animator/colour" android:name="square" /> </animated-vector>
Next we create a simple
intValue ObjectAnimator to change the colour from green to yellow:
?xml version="1.0" encoding="utf-8"?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:propertyName="fillColor" android:valueType="intType" android:repeatCount="1" android:repeatMode="reverse" android:interpolator="@android:interpolator/decelerate_cubic" android:valueFrom="@color/sa_green" android:valueTo="@color/vivid_yellow" />
So it’s perfectly OK to run multiple, simultaneous animators on the same pathe element resulting in the smooth transition from a green square to a yellow triangle (and back again thanks to the repeat on the animators):
It is worth re-iterating that all of the animations that we’ve seen in this series have been completed without any Java code other than a couple of lines required to start the animations. This is powerful stuff!
That concludes our look at VectorDrawables. Let’s keep our fingers crossed that theyll be coming to a support library very soon.
The source code for this article is available here.
© 2015, Mark Allison. All rights reserved.
Copyright © 2015 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.