一、前言
在 Android 中,矢量图是在 XML 中定义的一系列点、线、曲线,以及相关联的颜色信息。使用矢量图的主要优势是在缩放过程中不会损失显示质量(即不会模糊或者像素方格化),这就意味着一个矢量图可以缩放支持不同的屏幕,可以减少开发维护和消减 APK 文件的大小。另外,还可以为矢量图添加动画效果,详情参考:使用 AnimatedVectorDrawable。
本篇幅将介绍如何在 XML 中定义矢量图。还可以通过 Android Studio,将 SVG 格式图片转换成矢量图格式图片资源。但是需要注意的是,从 Android 5.0 (API level 21) 开始系统 API 才支持 VectorDrawable
和 AnimatedVectorDrawable
,如果需要在旧版本系统中使用,可以使用 Android 支持库实现(支持库对应 VectorDrawableCompat
和 AnimatedVectorDrawableCompat
两个类)。
注意事项:为了优化重绘的性能,每一个
VectorDrawable
都有一个位图缓存,因此引用同一个VectorDrawable
意味着使用相同的位图缓存。如果这些引用不是采用相同的尺寸,那么位图就会在每次尺寸改变的时候都会重新创建和绘制,换句话说,如果VectorDrawable
用于不同尺寸的情形,最高效的做法就是每一个尺寸创建一个VectorDrawable
。
二、VectorDrawable 详解
VectorDrawable
定义一个静态的绘制对象,跟 SVG 图片类似。VectorDrawable
的定义使用 XML 文件,是由 path
和 group
组成的树状层次结构,每一个 path
包含对象轮廓的几何图形,每一个 group
包含转换的详细信息,一个 group
内部可以包含多个 path
或者子 group
。所有的路径都会根据 XML 中定义顺序进行绘制。
2.1 VectorDrawable
定义节点详解
VectorDrawable
是用XML 资源文件定义的,包含的节点如下:
2.1.1 <vector>
节点
<vector>
节点是根节点,定义一个矢量图,节点内可使用的属性如下:
-
android:name
:定义矢量图的名称 -
android:width
:定义图像固有的宽度(支持所有的像素单位,通常使用dp
指定) -
android:height
:定义图像固有的高度(支持所有的像素单位,通常使用dp
指定) -
android:viewportWidth
:定义视口空间的宽度,视口基本是就是用来绘制路径的虚拟画布(换句话说就是虚拟画布的宽度,无像素单位) -
android:viewportHeight
:定义视口空间的高度,视口基本是就是用来绘制路径的虚拟画布(换句话说就是虚拟画布的搞度,无像素单位) -
android:tint
:定义绘可制图像着色颜色,默认没有着色 -
android:tintMode
:定义可绘制图像的混合着色模式,默认是src_in
-
android:autoMirrored
:指定可绘制图像在布局中的布局方向是 RTL(right-to-left)时是否自动镜像,默认 false -
android:alpha
:定义VectorDrawable
的透明度,取值 0.0~1.0,默认是 1.0
2.1.2 <group>
节点
<group>
节点定义多个路径或者子组 ,包含变换的详细信息。变换是在与视口相同的坐标中定义,并且按照缩放、旋转、平移的的顺序进行。该节点包含的属性如下:
-
android:name
:定义组的名称(用作标识) -
android:rotation
:设定组的旋转角度。默认是 0 -
android:pivotX
:设定组缩放和旋转的轴心点 X 坐标,在视口空间中定义,默认是 0 -
android:pivotY
:设定组缩放和旋转的轴心点 Y 坐标,在视口空间中定义,默认是 0 -
android:scaleX
:设定组在 X 轴方向上的缩放比例,默认值是 1 -
android:scaleX
:设定组在 Y 轴方向上的缩放比例,默认值是 1 -
android:translateX
:设定组在 X 轴方向的平移量,在视口空间中定义,默认是 0 -
android:translateY
:设定组在 Y 轴方向的平移量,在视口空间中定义,默认是 0
注意事项:节点属性中提到的 “在视口空间中定义”,即属性的值范围是视口大小范围,并不是图标大小范围。
2.1.3 <path>
节点
<path>
节点定义需要绘制的轨迹路径。该节点包含的属性如下:
-
android:name
:定义路径的名称(用作标识) -
android:pathData
:定义路径数据,使用跟 SVG 路径数据中 “d” 属性完全相同的格式定义。在视口控件中定义。 -
android:fillColor
:设定路径的填充颜色,可以是颜色值。在 API 24+,可以是带状态的颜色列表(ColorStateList
)或者渐变颜色。如果这个属性添加动画,动画中设置的只将覆盖原始值。如果没有指定改属性值,不会对路径进行填充。 -
android:strokeColor
:设定路径轮廓绘制的画笔颜色,可以是颜色值。在 API 24+,可以是带状态的颜色列表(ColorStateList
)或者渐变颜色,如果这个属性添加动画,动画中设置的只将覆盖原始值。如果没有指定改属性值,不会对路径进行填充。 -
android:strokeWidth
:设定路径轮廓绘制的画笔宽度,默认是 0(需先指定android:strokeColor
属性,值为 0 是最小宽度) -
android:strokeAlpha
:设定路径轮廓绘制的透明度,默认是1 (需先指定android:strokeColor
属性) -
android:fillAlpha
:设定路径的填充透明度,默认值是 1(需先指定android:fillColor
属性) -
android:trimPathStart
:设定路径从开始部分修剪的比例,取值范围 0 ~ 1,默认是 0 -
android:trimPathEnd
:设定路径从结尾部分修剪的比例,取值范围 0 ~ 1,默认是 0 -
android:trimPathOffset
:设定路径修剪位移(允许显示路径的开始和结束部分),取值范围 0 ~ 1,默认是0 -
android:strokeLineCap
:设定路径轮廓绘制的线帽,取值为butt
(对接)、round
(圆形) 和square
(方形),默认是butt
-
android:strokeLineJoin
:设定路径轮廓绘制的线条连接方式,取值为miter
(斜接)、round
(圆角)和bevel
(斜角), 默认是miter
-
android:strokeMiterLimit
:设定路径轮廓绘制的线条斜接极限(当android:strokeLineJoin="miter"
时有效),默认值是 4。 -
android:fillType
:设定路径填充类型,取值为evenOdd
或nonZero
,行为与 SVG 的 “fill-rule” 属性相同,默认值是nonZero
。此属性仅在 SDK 24+ 才有效。
2.1.4 <clip-path>
节点
<clip-path>
节点定义一个当前剪辑路径(注意:剪辑路径仅适用于当前组或者子级中)。该节点包含的属性如下:
-
android:name
:定义路径的名称(用作标识),该属性不可添加动画 -
android:pathData
:定义路径数据,使用跟 SVG 路径数据中 “d” 属性完全相同的格式定义。在视口控件中定义。该属性可添加动画。
2.2 VectorDrawable
定义
- 示例 XML
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:alpha="1.0">
<group
android:name="rotationGroup"
android:pivotX="10.0"
android:pivotY="10.0"
android:translateX="0"
android:rotation="15.0">
<path
android:name="vect"
android:fillAlpha=".3"
android:strokeColor="#FFFF0000"
android:strokeWidth="0.2"
android:strokeLineCap="butt"
android:strokeLineJoin="miter"
android:strokeMiterLimit="1"
android:fillType="nonZero"
android:fillColor="#FF000000"
android:pathData="M15.67,4H14V2h-4v2H8.33C7.6,4 7,4.6 7,5.33V9h4.93L13,7v2h4V5.33C17,4.6 16.4,4 15.67,4z" />
<path
android:name="draw"
android:fillColor="#FF000000"
android:strokeWidth="0.2"
android:strokeColor="#FF00FF00"
android:pathData="M13,12.5h2L11,20v-5.5H9L11.93,9H7v11.67C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33V9h-4v3.5z" />
</group>
</vector>
- 效果
2.3 创建 VectorDrawable
前面详细介绍了 VectorDrawable
,相信不少人到现在还对 android:pathData
这个字段的值一头雾水,这个字段的值如何获取的呢?显然,这个字符串值直接进行编辑是不现实的,尤其是比较复杂的图标。下面就介绍两种方法。
2.3.1 使用 Vector Asset Studio 创建 VectorDrawable
在Android Studio 中,自带了 Vector Asset Studio 工具,可以直接将 SVG 或者 PSD 格式源文件导入生成 VectorDrawable
,这是最简单的方式。
- 在项目的
res
目录下右键,打开 ”New -> Vector Asset“,打开 Vector Asset Studio。 - 在打开的 Vector Asset Studio 界面中,可以使用
Clip Art
选择已有的图标,也可以使用Local file(SVG, PSD)
导入源文件生成,设置好参数,根据向导就可以完成导入生成VectorDrawable
资源文件,资源 XML 文件放在res/drawable
目录下。
注意事项:
1. 如果导入的是 PSD 文件,必须保证 PSD 文件中存在路径,否则导入时无法识别到图标;
2. 使用导入的方式生成的VectorDrawable
,如果是 PSD 文件,坑能会丢失部分设计样式(比如描边),建议设计提供 SVG 格式文件。
2.3.2 根据 SVG 文件参数创建 VectorDrawable
SVG 文件,其实也是一个 XML 描述文件,可以根据里面的相关信息,自己创建 VectorDrawable
。
- 使用文本编辑器打开 SVG 文件,里面包含了图标的数据及相关绘制信息。在根节点
<svg>
中声明了图标大小,视口空间(viewport)大小等,在<style>
标签内部定义的是绘制的信息(填充颜色、画笔颜色、轮廓画笔宽度等等),<path>
标签为路径信息,“d“属性就是路径数据(pathData
)。
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000" viewBox="0 0 1000 1000">
<metadata><?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c138 79.159824, 2016/09/14-01:09:01 ">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""/>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?></metadata>
<defs>
<style>
.cls-1 {
fill: #333;
stroke: #12ff00;
stroke-linejoin: round;
stroke-width: 2px;
fill-rule: evenodd;
}
</style>
</defs>
<path id="形状_1" data-name="形状 1" class="cls-1" d="M705.047,324.4c-21.123,73.835-75.561,123.009-121.6,109.844-46.02-13.181-66.213-83.727-45.091-157.561,21.139-73.835,75.576-123.011,121.6-109.845S726.17,250.566,705.047,324.4ZM380.266,153.451c-47.278,7.555-75.79,75.158-63.685,150.992S376.821,435.652,424.1,428.1s75.8-75.15,63.685-150.985C475.692,201.269,427.543,145.9,380.266,153.451ZM199.8,362.354c-43.932,17.49-58.824,83.734-33.271,147.955S248.423,612.4,292.357,594.915s58.825-83.741,33.256-147.962S243.721,344.857,199.8,362.354Zm602.816,47.559c-43.476-18.6-100.743,17.855-127.913,81.411s-13.948,130.158,29.527,148.742,100.743-17.855,127.911-81.412S846.079,428.5,802.618,409.913ZM699.758,807.992c53.653-56.995-92.682-292.765-200-297.641-112.191-5.1-282.95,248.85-224.41,307.4s165.871,9.764,224.41,0S616.981,895.963,699.758,807.992Z"/>
</svg>
- 在
res/drawable
目录下创建一个 vector 资源xml,并将 SVG 文件的数据和绘制信息添加到VectorDrawable
中。
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="200dp"
android:height="200dp"
android:viewportWidth="1000"
android:viewportHeight="1000">
<path
android:name="cat_foot"
android:fillColor="#333"
android:strokeColor="#12ff00"
android:strokeWidth="2px"
android:strokeLineJoin="round"
android:pathData="M717.492,313.773c-22.4,78.3-80.147,130.454-128.974,116.491-48.814-13.978-70.233-88.793-47.829-167.1,22.422-78.3,80.163-130.456,128.975-116.494C718.492,160.653,739.9,235.47,717.492,313.773ZM373,132.479c-50.148,8.012-80.39,79.7-67.551,160.13s63.9,139.149,114.044,131.137,80.4-79.7,67.55-160.123C474.217,183.19,423.146,124.467,373,132.479ZM181.582,354.024c-46.6,18.548-62.395,88.8-35.29,156.908s86.862,108.275,133.463,89.727,62.395-88.809,35.274-156.917S228.167,335.468,181.582,354.024Zm639.4,50.438C774.87,384.738,714.127,423.4,685.309,490.8s-14.8,138.035,31.319,157.744S823.485,629.607,852.3,562.2,867.084,424.169,820.985,404.462Zm-109.1,422.169c56.91-60.445-98.307-310.483-212.138-315.654-119-5.411-300.122,263.911-238.03,326.007s175.938,10.355,238.03,0S624.081,919.927,711.882,826.631Z" />
</vector>
注意事项:
1. 如果 SVG 中包含多个路径,可能会有多个<style>
,每一个有不同的id,需要找到<path>
对应的<style>
Id;
2. 如果需要改变VectorDrawable
的大小,可更改android:width
和android:height
属性,但切记请勿改动android:viewportWidth
和android:viewportHeight
,必须和 SVG 中保持一致。
- AndroidStudio预览效果
2.4 在布局中使用 VectorDrawable
这个就不在这详细讲了,跟使用普通的 Drawable
没有啥区别。在前面也提到,为了提高性能,如果需要不同尺寸的 VectorDrawable
,请声明不同的资源文件。