Master Android VectorDrawable & AnimatedVectorDrawable: From SVG to Code and Animation
This article explains how Android handles SVG-like vector graphics using VectorDrawable and AnimatedVectorDrawable, covering their XML structures, supported tags, code examples, conversion from SVG, usage in layouts, and a detailed source code walkthrough of rendering and animation processes.
01 VectorDrawable
Android supports a subset of SVG features through VectorDrawable. The format uses an XML tree with a <vector> root and supports tags such as <group>, <path>, and <clip-path>. Attributes like android:name, android:fillColor, android:strokeColor, and android:pathData correspond closely to SVG attributes.
1.1 Elements and Attributes
The supported tags and attributes are defined in attrs.xml. The most common tag is <path>, whose pathData attribute uses the same command set as SVG (M, L, H, V, C, S, Q, T, A, Z).
<declare-styleable name="VectorDrawablePath">
<attr name="name" />
<attr name="strokeColor" format="color" />
<attr name="strokeWidth" format="float" />
<attr name="fillColor" format="color" />
<attr name="fillAlpha" format="float" />
<attr name="strokeAlpha" format="float" />
<attr name="pathData" format="string" />
<!-- other attributes omitted for brevity -->
</declare-styleable>1.2 Basic Shapes
Shapes are defined with <path> elements. Below is a simple test1.xml that draws a triangle, square, circle, and star.
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="40dp"
android:height="40dp"
android:viewportWidth="40"
android:viewportHeight="40">
<group
android:name="icon_group"
android:translateX="0"
android:translateY="0"
android:rotation="0">
<path
android:name="triangle"
android:fillColor="#00FF00"
android:pathData="M0,0 L0,10 L10,0z" />
<path
android:name="square"
android:fillColor="#00FF00"
android:pathData="M10,0 L20,0 L20,10 L10,10 Z" />
<path
android:name="circle"
android:fillColor="#00FF00"
android:pathData="M0,18 A5,5 0 1,1 10,18 A5,5 0 1,1 0,18 Z" />
<path
android:name="star"
android:fillColor="#00FF00"
android:pathData="M16,13 L17,17 21,17 18,19 20,23 16,20 12,23 14,19 11,17 15,17 Z" />
</group>
</vector>1.3 Transformations
The <group> tag supports rotation, translation, and scaling, while <path> does not. By moving <path> elements into a <group>, you can apply the same transformation to multiple shapes.
<vector ...>
<group
android:name="icon_group"
android:translateX="10"
android:translateY="0"
android:rotation="10">
<path
android:name="triangle"
android:fillColor="#00FF00"
android:strokeColor="#FF0000"
android:strokeWidth="0.5"
android:pathData="M0,0 L0,10 L10,0z" />
<!-- other paths omitted for brevity -->
</group>
</vector>1.4 Gradients
Both fillColor and strokeColor can reference gradient resources using the aapt:attr tag.
<vector ...>
<path
android:name="oval1"
android:strokeColor="#ff0000"
android:strokeWidth="2"
android:pathData="M10,60 a30,40 0 1,0 80,0 a30,40 0 1,0 -80,0">
<aapt:attr name="android:fillColor">
<gradient
android:startX="0"
android:startY="0"
android:endX="0"
android:endY="100"
android:type="linear">
<item android:offset="0" android:color="#FF0000"/>
<item android:offset="1" android:color="#0000FF"/>
</gradient>
</aapt:attr>
</path>
</vector>1.5 Clip Path
The <clip-path> tag defines a clipping region for subsequent drawing commands.
<vector ...>
<group>
<clip-path
android:name="clip1"
android:pathData="M0,0 h100 v80 h-100 Z" />
<path
android:name="oval1"
android:fillColor="#0000ff"
android:strokeColor="#ff0000"
android:strokeWidth="2"
android:pathData="M10,60 a30,40 0 1,0 80,0 a30,40 0 1,0 -80,0 Z" />
</group>
</vector>1.6 Importing SVG
Android Studio’s Vector Asset tool can import system vector assets or local SVG files. Simple SVGs that contain only <path> elements convert cleanly; more complex SVGs may require manual adjustments.
02 AnimatedVectorDrawable
Android does not support SVG animation tags. Instead, AnimatedVectorDrawable combines a static VectorDrawable with property animations defined by ObjectAnimator or AnimatorSet.
2.1 Elements and Attributes
The root tag is <animated-vector> with a required android:drawable attribute that references a VectorDrawable. Each <target> specifies the name of a vector element and an animation resource.
<declare-styleable name="AnimatedVectorDrawable">
<attr name="drawable" />
</declare-styleable>
<declare-styleable name="AnimatedVectorDrawableTarget">
<attr name="name" />
<attr name="animation" />
</declare-styleable>2.2 Using Animated Vectors
Below is test8.xml, which animates a simple check‑mark into a cross while changing its stroke color.
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
<aapt:attr name="android:drawable">
<vector android:width="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportHeight="24">
<path android:name="root"
android:strokeWidth="2"
android:strokeLineCap="square"
android:strokeColor="#FF0000"
android:pathData="M4.8,13.4 L9,17.6 M10.4,16.2 L19.6,7" />
</vector>
</aapt:attr>
<target android:name="root">
<aapt:attr name="android:animation">
<objectAnimator
android:propertyName="pathData"
android:valueFrom="M4.8,13.4 L9,17.6 M10.4,16.2 L19.6,7"
android:valueTo="M6.4,6.4 L17.6,17.6 M6.4,17.6 L17.6,6.4"
android:duration="6000"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:valueType="pathType" />
</aapt:attr>
</target>
<target android:name="root">
<aapt:attr name="android:animation">
<objectAnimator
android:propertyName="strokeColor"
android:valueFrom="#FF0000"
android:valueTo="#0000FF"
android:duration="6000"
android:interpolator="@android:interpolator/fast_out_slow_in"
android:valueType="colorType" />
</aapt:attr>
</target>
</animated-vector>Use the drawable in a layout:
<ImageView
android:id="@+id/img_2"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/test8" />Start the animation in code:
ImageView imageView = findViewById(R.id.img_2);
AnimatedVectorDrawable avd = (AnimatedVectorDrawable) imageView.getDrawable();
if (avd != null) {
avd.start();
}2.3 Source Code Walkthrough
The Android framework parses animated-vector in DrawableInflater.inflateFromTag, creates an AnimatedVectorDrawable, and calls its inflate method. Inside AnimatedVectorDrawable.inflate the drawable attribute is resolved to a VectorDrawable, and each target loads an Animator (usually an ObjectAnimator) via AnimatorInflater.loadAnimator.
// DrawableInflater.java (simplified)
Drawable drawable = inflateFromTag(name);
if (drawable == null) {
drawable = inflateFromClass(name);
}
drawable.inflate(mRes, parser, attrs, theme);
return drawable;
// AnimatedVectorDrawable.inflate(...)
if (ANIMATED_VECTOR.equals(tagName)) {
TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.AnimatedVectorDrawable);
int drawableRes = a.getResourceId(R.styleable.AnimatedVectorDrawable_drawable, 0);
if (drawableRes != 0) {
VectorDrawable vectorDrawable = (VectorDrawable) res.getDrawable(drawableRes, theme).mutate();
state.mVectorDrawable = vectorDrawable;
}
a.recycle();
} else if (TARGET.equals(tagName)) {
TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.AnimatedVectorDrawableTarget);
String target = a.getString(R.styleable.AnimatedVectorDrawableTarget_name);
int animResId = a.getResourceId(R.styleable.AnimatedVectorDrawableTarget_animation, 0);
if (animResId != 0) {
Animator animator = AnimatorInflater.loadAnimator(res, theme, animResId, pathErrorScale);
updateAnimatorProperty(animator, target, state.mVectorDrawable, state.mShouldIgnoreInvalidAnim);
state.addTargetAnimator(target, animator);
}
a.recycle();
}The method updateAnimatorProperty binds the animator’s PropertyValuesHolder to the corresponding vector element’s Property (e.g., VFullPath.PATH_DATA).
private static void updateAnimatorProperty(Animator animator, String targetName,
VectorDrawable vectorDrawable, boolean ignoreInvalidAnim) {
if (animator instanceof ObjectAnimator) {
PropertyValuesHolder[] holders = ((ObjectAnimator) animator).getValues();
for (PropertyValuesHolder pvh : holders) {
String propertyName = pvh.getPropertyName();
Object targetObj = vectorDrawable.getTargetByName(targetName);
Property property = null;
if (targetObj instanceof VectorDrawable.VObject) {
property = ((VectorDrawable.VObject) targetObj).getProperty(propertyName);
}
if (property != null && containsSameValueType(pvh, property)) {
pvh.setProperty(property);
}
}
} else if (animator instanceof AnimatorSet) {
for (Animator child : ((AnimatorSet) animator).getChildAnimations()) {
updateAnimatorProperty(child, targetName, vectorDrawable, ignoreInvalidAnim);
}
}
}When the animation starts, AnimatedVectorDrawable.start() creates an AnimatorSet that drives the ObjectAnimator. The animation loop is driven by Android’s Choreographer via AnimationHandler. Each frame calls ObjectAnimator.calculateValue, which uses a PathDataEvaluator to interpolate between the start and end PathData. The resulting PathParser.PathData is set on the vector element through the static Property<VPath, PathData> PATH_DATA defined in VectorDrawable.VPath. Finally, the updated vector is drawn by VectorDrawable.draw(), which delegates to native rendering code.
03 Summary
VectorDrawable provides a lightweight, tree‑structured format for static vector graphics on Android. It supports a limited set of tags ( vector, group, path, clip-path) and attributes that map closely to SVG, making it ideal for icons and simple UI elements.
AnimatedVectorDrawable extends this model with property animations. By linking ObjectAnimator (or AnimatorSet) to vector elements, developers can animate path data, colors, and other properties without external libraries. The animation engine reuses Android’s core animation framework (Animator, Choreographer) and performs path interpolation in native code for performance.
Both formats are compact, resolution‑independent, and integrate seamlessly with Android layouts, offering a powerful way to create crisp, animated UI components.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
