Your App icon as AnimatedVectorDrawable

Since API level 21 we got access to VectorDrawable and AnimatedVectorDrawable, making assets in Android more accessible and powerful to work with.

We thought it would be a good idea to explain the process of how I took a logo and converted it into a loading animation.

In this blog post, we guide you through the steps we did to make it happen.

For that, we’re going to use the Exchange Deal logo as example.

Exchange Deal App icon

The icon as VectorDrawable

It’s possible that your App icon isn’t a SVG format or designed with paths in mind. If you want to create it from scratch, you can use multiple design tools to create it in that way. Let’s see how we can achieve this:

We started creating a grid (128x128px) that would help us getting the coordinates. For this, you can use the design tool you like most: Illustrator, Photoshop, Sketch… Up to you!

Create the grid

Then, step by step, we build the icon and take notes of the coordinates and distances to introduce them in Android Studio later on.

First circle of the icon

As you can see, the logo is composed by 5 circles. Start simple and build on the solution.

To understand more about VectorDrawable paths, you can refer to the documentation. There’s also a good article in Medium that talks about pathData commands, link here.

To draw a circle, we are going to move the cursor to the top part of it draw two paths (one for the right and the other one for the left part) to the bottom part. As we can see in the picture above, the circle has a diameter of 76.5px and the top part starts on the coordinate (64,26).

We can represent that as a VectorDrawable in Android Studio like:

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="80dp"
android:width="80dp"
android:viewportHeight="128"
android:viewportWidth="128">

<group android:name="firstCircle">
<path android:fillColor="#00000000"
android:pathData="M64,26 a1,1 0 0,0 0,76.5"
android:strokeColor="#000000"
android:strokeWidth="1"/>

<path android:fillColor="#00000000"
android:pathData="M64,26 a1,1 0 1,1 0,76.5"
android:strokeColor="#000000"
android:strokeWidth="1"/>
</group>
</vector>

As you can see, the image has a height and width of 80dp but we’re drawing in a canvas of 128x128px (the same dimension as the sketch). The beauty of VectorDrawables is that we can increase the size of the image without affecting the way it’s drawn.

If we continue and cover all the circles we’ll get something like this:

VectorDrawable seen in Android Studio

Here is the code

File name: res/drawable/ed_logo.xml
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="80dp"
android:width="80dp"
android:viewportHeight="128"
android:viewportWidth="128">

<group android:name="firstCircle">
<path android:fillColor="#00000000"
android:pathData="M64,26 a1,1 0 0,0 0,76.5"
android:strokeColor="#000000"
android:strokeWidth="1"/>

<path android:fillColor="#00000000"
android:pathData="M64,26 a1,1 0 1,1 0,76.5"
android:strokeColor="#000000"
android:strokeWidth="1"/>
</group>

<group android:name="secondCircle">
<path android:fillColor="#00000000"
android:pathData="M67,27.5 a1,1 0 0,0 0,76.5"
android:strokeColor="#000000"
android:strokeWidth="1"/>

<path android:fillColor="#00000000"
android:pathData="M67,27.5 a1,1 0 1,1 0,76.5"
android:strokeColor="#000000"
android:strokeWidth="1"/>
</group>

<group android:name="thirdCircle">
<path android:fillColor="#00000000"
android:pathData="M60,28 a1,1 0 0,0 0,76.5"
android:strokeColor="#000000"
android:strokeWidth="1"/>

<path android:fillColor="#00000000"
android:pathData="M60,28 a1,1 0 1,1 0,76.5"
android:strokeColor="#000000"
android:strokeWidth="1"/>
</group>

<group android:name="fourthCircle">
<path android:fillColor="#00000000"
android:pathData="M66,32.5 a1,1 0 0,0 0,76.5"
android:strokeColor="#000000"
android:strokeWidth="1"/>

<path android:fillColor="#00000000"
android:pathData="M66,32.5 a1,1 0 1,1 0,76.5"
android:strokeColor="#000000"
android:strokeWidth="1"/>
</group>

<group android:name="fifthCircle">
<path android:fillColor="#00000000"
android:pathData="M61,32.5 a1,1 0 0,0 0,76.5"
android:strokeColor="#000000"
android:strokeWidth="1"/>

<path android:fillColor="#00000000"
android:pathData="M61,32.5 a1,1 0 1,1 0,76.5"
android:strokeColor="#000000"
android:strokeWidth="1"/>
</group>
</vector>

Android Implementation

How does what we’ve done so far look like in an Android app?

There are multiple articles about how to use VectorDrawables: Chris Banes, Mark Allison, … In our project, we did the following:

In your Gradle file, make sure you have the vectorDrawables.useSupportLibrary option enabled:

ext {
supportLibVersion = '24.2.1'
}

dependencies {
compile "com.android.support:appcompat-v7:${supportLibVersion}"
compile "com.android.support:design:${supportLibVersion}"
    ...
}

android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
minSdkVersion 16
targetSdkVersion 24
...
}
}

Now, we can create a simple layout and show it.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<ImageView
android:id="@+id/logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:srcCompat="@drawable/ed_logo"/>

</LinearLayout>
Logo as VectorDrawable

Animating VectorDrawables

Now that we have the VectorDrawable in place, let’s create a simple loading animation. We’re going to create a funny effect rotating each circle on its centre.

For that, we create an animator that’s going to animate a certain path (in this case, each circle). Create a file under the ./res/anim folder:

File name: res/anim/rotation.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:interpolator="@android:anim/linear_interpolator"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360"
android:repeatCount="infinite"
android:repeatMode="restart"
android:duration="600"
android:valueType="floatType"/>
</set>

Once we have the animator for a path, we have to create an animated-vector drawable file in the ./res/drawable folder.

File name: res/drawable/ed_logo_loading_animation.xml
<?xml version="1.0" encoding="utf-8"?>
<animated-vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ed_logo">

<target
android:name="firstCircle"
android:animation="@anim/rotation"/>
<target
android:name="secondCircle"
android:animation="@anim/rotation"/>
<target
android:name="thirdCircle"
android:animation="@anim/rotation"/>
<target
android:name="fourthCircle"
android:animation="@anim/rotation"/>
<target
android:name="fifthCircle"
android:animation="@anim/rotation"/>

</animated-vector>

In order to allow this rotation, we have to modify the @drawable/ed_logo slightly. For each circle, we’d have to define (and calculate) the pivot in which the circle is going to rotate. In our case:

File name: res/drawable/ed_logo.xml
...
<group android:name="firstCircle"
android:pivotX="64"
android:pivotY="64">
       ...
</group>
<group android:name="secondCircle"
android:pivotX="67"
android:pivotY="66">
       ...
</group>
<group android:name="thirdCircle"
android:pivotX="60"
android:pivotY="66">
       ...
</group>
<group android:name="fourthCircle"
android:pivotX="66"
android:pivotY="71">

...
</group>
<group android:name="fifthCircle"
android:pivotX="61"
android:pivotY="71">
       ...
</group>

Everything is good to go now, we can use the same layout in which we showed the static image previously. The source of the image is the AnimatedVectorDrawable we just created.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<ImageView
android:id="@+id/logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:srcCompat="@drawable/ed_logo_loading_animation"/>

</LinearLayout>

We also need to run the animation. For that, we go to the Activity/Fragment in which the image is being displayed and start the animation:

ImageView exchangeDealLogoImageView = (ImageView) getActivity().findViewById(R.id.logo);
Drawable drawable = exchangeDealLogoImageView.getDrawable();
if (drawable instanceof Animatable) {
((Animatable) drawable).start();
}
Animated Exchange Deal icon

Roman Nurik has been working on this Android Icon Animator that will help you test out your animations before putting that in code.

Check out the code at my Github repo.

Exchange Deal

Exchange Deal is available for both Android and iOS.

Thanks for reading,

Manuel Vicente Vivo