Monday, October 20, 2014

First look at AnimatedVectorDrawable

Android Lollipop introduced a lot of sweet new classes. The one that caught my eye is AnimatedVectorDrawable, and I decided to check it out right away.

Example from Documentation

The documentation included an example, so I created the files as instructed: res/drawable/vectordrawable.xml, res/drawable/avd.xml, res/anim/rotation.xml and res/anim/path_morph.xml

Now what? There are many ways to use a Drawable. How about in a TextView?

<TextView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@string/example_from_documentation"
  android:drawableBottom="@drawable/avd"/>

No animation yet. Let's start it.

for (Drawable drawable : textView.getCompoundDrawables()) {
  if (drawable instanceof Animatable) {
    ((Animatable) drawable).start();
  }
}

And voilĂ ! Animation. But what is it? Let's step it through.

res/drawable/vectordrawable.xml

<vector
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:height="64dp"
  android:width="64dp"
  android:viewportHeight="600"
  android:viewportWidth="600" >
  <group
    android:name="rotationGroup"
    android:pivotX="300.0"
    android:pivotY="300.0"
    android:rotation="45.0" >
    <path
      android:name="v"
      android:fillColor="#000000"
      android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
  </group>
</vector>

This is the VectorDrawable. The path defines a triangle, and the group rotates it by 45 degrees.

res/drawable/avd.xml

<animated-vector
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:drawable="@drawable/vectordrawable" >
  <target
    android:name="rotationGroup"
    android:animation="@anim/rotation" />
  <target
    android:name="v"
    android:animation="@anim/path_morph" />
</animated-vector>

Next we have avd.xml, which rotates the group and morphs the path.

res/anim/rotation.xml

<objectAnimator
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:duration="6000"
  android:propertyName="rotation"
  android:valueFrom="0"
  android:valueTo="360" />

res/anim/path_morph.xml

<set
  xmlns:android="http://schemas.android.com/apk/res/android">
  <objectAnimator
    android:duration="3000"
    android:propertyName="pathData"
    android:valueFrom="M300,70 l 0,-70 70,70 0,0   -70,70z"
      android:valueTo="M300,70 l 0,-70 70,0  0,140 -70,0 z"
    android:valueType="pathType"/>
</set>

The rotation starts from 0 degrees. But since our drawable is initially rotated at 45 degrees, there is a sudden jump when the animation starts. It takes 6000ms to reach 360 degrees. Meanwhile, the path morphs from a triangle to a rectangle in 3000ms, half the time. So, at 180 degrees, the morph is complete.

Phew, that was not obvious at all. To understand what was happening, I split the rotation and the path morph to observe them separately.

Clock

After trying the example, I wanted to make my own, to see if I can come up with some simple animations that makes sense. I like the idea of animating different parts of the VectorDrawable, and made a clock.

The hours arm rotates from 9 o'clock to 5 o'clock while the minutes arm goes around from 0 to 60 minutes. The duration of rotations are set differently to give them different speeds.

Smiling face

Next I played with path morph. What is a path morph that makes sense? Let's make a sad face into a happy face!

Points to note

  1. The <vector> tag must have android:height and android:width to define the intrinsic width and height of the VectorDrawable. Your app will crash if you skip them.
  2. If your VectorDrawable has a smaller android:height or android:width than when you use them say in an ImageView, your graphic will look pixelated.
  3. To morph from one path to another, the paths must be compatible. They need to have the exact same length of commands, and exact same length of parameters for each command.

I am very excited about VectorDrawable and AnimatedVectorDrawable. Scalable graphics FTW!

Source code: https://github.com/chiuki/animated-vector-drawable

8 comments:

Inline coding questions will not be answsered. Instead, ask on StackOverflow and put the link in the comment.

  1. I have made online tool for converting SVG into xml resource vector - http://inloop.github.io/svg2android/ - It was not tested so much still in early alpha. It support simple svg files (as android supports), I have tested It with inkscape - drawed some shapes (rect,circle,spiral...), select all then "Path->Object to path", exported into *.svg and dropped into site, generated xml and works fine.

    ReplyDelete
    Replies
    1. You should definetly promote that tool ... it saved my life :P

      Delete
    2. Juraj, your converter kills all animation in SVG file. Perhaps you should add animation support to your tool as well.

      Delete
  2. nice tutorial, really appreciate your work

    ReplyDelete
  3. Very interesting article. VectorDrawables with animations open the gate to a world of endless possibilities. I want to do fancy things with complex vector images.

    ReplyDelete
  4. that is superb... but there is this https://github.com/bonnyfone/vectalign which can help with morphing for non-compatible path

    ReplyDelete