AnimatedVectorDrawable / Drawables / VectorDrawable

VectorDrawables – Part 4

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:

square_drawable

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.

My specifying 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.

7 Comments

  1. Great series of articles. I am really looking forward to being able to actually use this (either only support 5.0+, or this is somehow supported in earlier versions).

    This sort of graphical control (and ease) is really amazing, and will allow for some really nice animations and customizations. I need a lot of these tools for my current project, but will have to learn how to do these animations the old way (I bet there are some good articles in your archives). I only support back to 4.3 (I require BLE) which is reasonably new, but not new enough.

    Cheers, and thanks again. If you are ever in Phoenix, beers are on me.

  2. Hi,

    I have a question regarding pathData.
    android:pathData=”M100,100 L400,100 L400,400 L100,400 z”

    You have mentioned “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”.

    I assume it is in the format L(x,y).So shouldn’t L400,400 means drawing lines from bottom right to the top right corner and L100,400 means top right to top left?

    Sorry if this is silly question.

  3. Could you please talk about morphing animation and controlling it via java code, it seems we cann’t use ObjectAnimator class in java to control the morphing animation. I mean animations with pathType property (valueType = “pathType”) does not start if you try to start it from java code. Could you give it a shot?

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.