Android VectorDrawable是一套基于XML的矢量图绘制方案,最早在Android 5.0引入。它的核心思想不是存储像素点,而是用<vector>节点下的<path>路径数据描述图形轮廓。APK打包时这些XML文件会被编译为二进制资源,运行时由系统或兼容库解析并绘制。与位图相比,VectorDrawable的最大优势是可以适配不同屏幕密度,不需要为mdpi、hdpi、xhdpi、xxhdpi分别提供PNG,同时在旋转、缩放场景下不会出现边缘锯齿。但它的使用并不是简单替换图片资源,还涉及兼容配置、动画实现和性能取舍。

VectorDrawable结构认识与pathData命令解析
一个最小化的矢量资源以<vector>作为根节点,它通常包含android:width、android:height、android:viewportWidth和android:viewportHeight四个属性。其中width和height表示资源在绘制时的逻辑宽高,单位一般为dp;viewportWidth和viewportHeight则定义内部坐标系,例如24乘24表示所有路径点都落在该坐标范围内。这个坐标系统不与屏幕像素绑定,因此图形可以无损缩放。
真正负责描绘形状的是<path>节点。每个path通过android:pathData携带一组绘图指令,并配合android:fillColor、android:strokeColor、android:strokeWidth控制填充色、描边色和描边宽度。pathData使用类似SVG路径的命令语言,常用命令如下:M表示移动到绝对坐标,m表示相对移动;L表示画直线,l表示相对直线;H和V分别绘制水平与垂直线;C用于三次贝塞尔曲线,Q用于二次贝塞尔曲线;A用于绘制圆弧;Z表示闭合路径。小写命令基于当前点计算,大写命令基于原点绝对坐标计算。
下面是一个典型的对勾图标定义。资源内部没有像素数据,只有路径字符串和颜色信息,因此文件体积极小。实际解析时系统会把这些路径渲染到指定尺寸的画布上。
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:name="check_path"
android:fillColor="#FF000000"
android:pathData="M4,12L10,18L20,6"
android:strokeWidth="2"/>
</vector>
pathData解析比较严格,数字之间通常用逗号或空白分隔。如果路径命令中缺少坐标数量,或者使用了系统不支持的指令,编译或运行时会抛出异常。开发者还可以通过android:fillType控制重叠区域的填充规则,可选值为evenOdd与nonZero。对于环形或镂空图形,选错fillType会让中间区域被错误填满,这是很多自定义图标的常见问题。
工程配置与低版本使用方案
VectorDrawable原生只支持Android 5.0及以上版本,也就是API级别21。如果应用还需要覆盖更低版本,必须引入AndroidX的矢量图兼容库。在模块级build.gradle文件中,需要添加androidx.vectordrawable:vectordrawable依赖,并在defaultConfig中开启vectorDrawables.useSupportLibrary = true。该配置允许兼容库处理矢量资源解析,使API 21以下设备也能加载VectorDrawable。
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
dependencies {
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
}
光开启依赖还不够,XML布局中的加载方式同样会影响低版本兼容性。通常不能直接在<ImageView>上使用android:src引用VectorDrawable,因为API 21以下的系统控件不认识这种资源类型。正确做法是使用app:srcCompat属性,并确保根布局引入app命名空间。示例布局如下。
<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="wrap_content">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
app:srcCompat="@drawable/ic_check_vector"
android:contentDescription="矢量图标"/>
</LinearLayout>
对于<Button>、<TextView>的android:drawableLeft、android:drawableStart等属性,低版本同样无法直接识别VectorDrawable。此时可以在Application初始化阶段调用AppCompatDelegate.setCompatVectorFromResourcesEnabled(true),或者改用代码方式设置CompoundDrawable。还有一点需要注意,如果项目已经迁移到AndroidX,应统一使用androidx.appcompat.widget.AppCompatImageView,避免混用旧版support控件导致资源加载失败。
AnimatedVectorDrawable动画实现与复杂场景
VectorDrawable本身只能描述静态图形,如果希望图标动起来,需要借助AnimatedVectorDrawable。它的原理是把ObjectAnimator动画绑定到矢量资源的某个<path>节点上,通过修改path的trimPathStart、trimPathEnd、fillColor、translateX等属性实现描边、变色、位移动画。比如一个圆形进度圈,可以通过改变trimPathEnd从0到1,让路径逐渐显现,模拟进度绘制过程。
实现时首先需要定义一个带有path名称的VectorDrawable,然后创建animated-vector资源,把动画目标指向对应path。下面示例展示了一个简单的路径裁剪动画,静态矢量中path名为arc_path,动画资源对该path执行trimPathEnd变化。
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="32"
android:viewportHeight="32">
<path
android:name="arc_path"
android:pathData="M16,4A12,12 0 1 1 15.9,4"
android:strokeColor="#FF3F51B5"
android:strokeWidth="3"
android:fillColor="@android:color/transparent"/>
</vector>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ic_arc_vector">
<target
android:name="arc_path"
android:animation="@animator/arc_trim_animation"/>
</animated-vector>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="800"
android:propertyName="trimPathEnd"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType"/>
启动动画时,可以使用AnimatedVectorDrawableCompat包裹资源,这样在低版本设备上也能正常运行。示例代码先创建兼容实例,再设置给ImageView并调用start方法。动画会在主线程触发重绘,如果同时运行多个复杂路径动画,可能造成掉帧。
AnimatedVectorDrawableCompat avd = AnimatedVectorDrawableCompat.create(this, R.drawable.animated_arc);
if (avd != null) {
imageView.setImageDrawable(avd);
avd.start();
}
VectorDrawable动画适合轻量、短促的交互反馈,比如开关状态切换、下拉刷新图标旋转、菜单按钮变形等。对于逐帧复杂角色动画或带有大量贝塞尔曲线形变的场景,VectorDrawable的路径计算开销会明显上升。此时不如使用Lottie或其他序列帧方案。另一个优化建议是尽量控制动画时长和重复次数,避免在RecyclerView的可见项中同时播放大量矢量动画,否则容易引发过度测量和绘制。
常见误区与排查清单
第一个常见误区是仍然使用android:src加载矢量图。很多开发者在预览时看到图标正常显示,但到低版本真机上就崩溃。原因在于预览设备往往运行在高API级别,而低版本系统控件根本不支持VectorDrawable。排查时可以检查布局中是否使用app:srcCompat,以及Gradle中是否开启useSupportLibrary。
第二个误区是以为所有SVG都可以直接导入使用。实际上Android Studio的Vector Asset导入功能会对SVG进行转换,某些滤镜、文本、嵌套遮罩和复杂渐变可能无法完整转换。尤其是渐变支持,原生VectorDrawable的本质渐变只在API 24及以上可用,兼容库对部分渐变支持并不完整。如果图标依赖复杂渐变,建议在低版本上准备PNG或WebP兜底资源。
第三个误区是动画target的name写错导致动画静默无效。animated-vector中的android:name必须与静态vector中path的android:name完全一致。字符大小写、下划线、空格不同都会造成动画不执行。排查时可以先简化动画,只保留一个target,确认path名后逐步增加。另一个问题是pathData动画在部分设备上可能不支持,应优先使用trimPath、旋转、缩放等属性动画。
最后给出一个快速排查顺序:先确认资源根节点是<vector>而非<layer-list>;检查width、height和viewport比例是否合理;检查低版本是否使用app:srcCompat;检查动画target的name是否匹配;检查复杂渐变是否只在API 24以上使用;检查是否有过大的pathData导致解析缓慢。通过这些步骤,大多数VectorDrawable加载和显示问题都能快速定位。
VectorDrawableAndroid矢量图矢量图动画修改时间:2026-08-28 11:18:26