矢量图像资源详解(Vector drawables)

一、前言

    在 Android 中,矢量图是在 XML 中定义的一系列点、线、曲线,以及相关联的颜色信息。使用矢量图的主要优势是在缩放过程中不会损失显示质量(即不会模糊或者像素方格化),这就意味着一个矢量图可以缩放支持不同的屏幕,可以减少开发维护和消减 APK 文件的大小。另外,还可以为矢量图添加动画效果,详情参考:使用 AnimatedVectorDrawable

    本篇幅将介绍如何在 XML 中定义矢量图。还可以通过 Android Studio,将 SVG 格式图片转换成矢量图格式图片资源。但是需要注意的是,从 Android 5.0 (API level 21) 开始系统 API 才支持 VectorDrawableAnimatedVectorDrawable,如果需要在旧版本系统中使用,可以使用 Android 支持库实现(支持库对应 VectorDrawableCompatAnimatedVectorDrawableCompat 两个类)。

注意事项:为了优化重绘的性能,每一个 VectorDrawable 都有一个位图缓存,因此引用同一个 VectorDrawable 意味着使用相同的位图缓存。如果这些引用不是采用相同的尺寸,那么位图就会在每次尺寸改变的时候都会重新创建和绘制,换句话说,如果 VectorDrawable 用于不同尺寸的情形,最高效的做法就是每一个尺寸创建一个 VectorDrawable

二、VectorDrawable 详解

    VectorDrawable 定义一个静态的绘制对象,跟 SVG 图片类似。VectorDrawable 的定义使用 XML 文件,是由 pathgroup 组成的树状层次结构,每一个 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:设定路径填充类型,取值为 evenOddnonZero,行为与 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>
  • 效果
    VectorDrawable实现的电池图标

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
  • 在打开的 Vector Asset Studio 界面中,可以使用 Clip Art 选择已有的图标,也可以使用 Local file(SVG, PSD) 导入源文件生成,设置好参数,根据向导就可以完成导入生成 VectorDrawable 资源文件,资源 XML 文件放在 res/drawable 目录下。
    Vector Asset Studio导入资源生成VectorDrawable

注意事项:
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:widthandroid:height 属性,但切记请勿改动 android:viewportWidthandroid:viewportHeight ,必须和 SVG 中保持一致。

  • AndroidStudio预览效果
    预览效果

2.4 在布局中使用 VectorDrawable

    这个就不在这详细讲了,跟使用普通的 Drawable 没有啥区别。在前面也提到,为了提高性能,如果需要不同尺寸的 VectorDrawable,请声明不同的资源文件。

Android Vector 资源是一种矢量图形格式,与传统的位图不同,它是由一系列的矢量图形命令描述的,可以实现无限缩放而不失真,而且占用的空间比位图小得多。在 Android 开发中,使用 Vector 资源可以有效地减少应用的安装包大小,提高应用的性能。 要创建一个 Vector 资源,可以按照以下步骤进行操作: 1. 在 res/drawable 目录下创建一个 XML 文件,例如 ic_vector.xml。 2. 在 XML 文件中使用 `<vector>` 标签来定义一个 Vector 图形,例如: ```xml <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24.0" android:viewportHeight="24.0"> <path android:fillColor="#FF000000" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM8.55,15.03l-2.83,-2.83 1.41,-1.41 1.42,1.42 4.24,-4.24 1.41,1.41 -5.65,5.65z"/> </vector> ``` 其中,`<vector>` 标签用于定义 Vector 图形的属性,例如宽度、高度和视口大小等;`<path>` 标签用于定义 Vector 图形的路径,例如填充颜色和路径数据等。使用 Vector 图形的具体语法和属性可以参考官方文档。 3. 在布局文件或代码中使用 Vector 资源,例如: ```xml <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" app:srcCompat="@drawable/ic_vector" /> ``` ```java ImageView imageView = findViewById(R.id.image_view); Drawable drawable = VectorDrawableCompat.create(getResources(), R.drawable.ic_vector, null); imageView.setImageDrawable(drawable); ``` 需要注意的是,使用 Vector 资源需要在 app/build.gradle 文件中添加以下代码,以支持 API 级别 21 及以下的设备: ```groovy android { defaultConfig { vectorDrawables.useSupportLibrary = true } } dependencies { implementation 'com.android.support:appcompat-v7:28.0.0' } ``` 其中,vectorDrawables.useSupportLibrary = true 表示使用支持库中的 VectorDrawableCompat 类来加载 Vector 资源
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值