一、Vector
优点
VectorDrawable
主要有两个优点:屏幕自适应和体积小。
- 如果我们使用的是普通的
png
或者jpg
图片,那么为了能让图片在不同分辨率的机型上能够很好地展现,通常会在各个drawable
文件夹下放置不同分辨率大小的图片文件,而VectorDrawable
则不需要,仅仅只使用一套资源,就能够适应任何分辨率的手机。 - 对于某些图片,
VectorDrawable
素材的大小要比png
和jpg
小很多。
二、SVG
和Vector
的基本概念
下面,我们先介绍一下SVG
和VectorDrawable
的基本概念:
-
SVG
:它并不是Android
平台特有的概念,它的全称为可缩放矢量图形,简单的来说,就是用于描述二维矢量图形的图形格式,更加详细的解释可以参考:SVG - 百度百科。 -
VectorDrawable
:它是Android
当中的SVG
实现,它并不支持SVG
的全部语法,只是支持部分有必要的部分。
三、获取VectorDrawable
俗话说的好,巧妇难为无米炊,这一节我们就来介绍一下如何获得一个VectorDrawable
,一般获取的方式有以下三种方式:
- 先获取
SVG
素材,再通过工具转换成为VectorDrawable
- 通过
Android Studio
中的素材库,直接获取VectorDrawable
- 根据
Vector
的语法,自己描述
3.1 先获取SVG
素材,再通过工具转换成为VectorDrawable
首先获取SVG
素材,再将它转换成为VectorDrawable
是最常用的方式,而SVG
素材的获取又有以下几种途径:
- 网站直接下载
SVG
图像 - 由
UI
设计师使用专业的工具导出 - 通过 VectorMagic 软件,将
png
和jpg
素材转换为SVG
图像
对于个人开发者而言,一般都会采用第一种方式,我们这里也只介绍第一种方式。很多文章都推荐过这个网站:iconFront - 阿里巴巴,它提供了SVG
和PNG
素材的直接下载:
下载完毕之后,在
Android Studio
的
New
选项中,选择
Vector Asset
:
打开之后,选择
Local file
,并打开我们下载后的图像,再选择
next
保存到指定的文件夹:
最后,我们会得到一个
*.xml
文件,这个就是
VectorDrawable
:
3.2 通过Android Studio
中的素材库,直接获取VectorDrawable
还是在上面的那个界面,我们勾选另外一个选项:
这里面有
Material Design
提供的素材库:
通过这种方式,同样可以获取到一个
*.xml
的
VectorDrawable
:
3.3 根据Vector
的语法,自己描述
在3.1
和3.2
当中,我们可以看到,最终VectorDrawable
都是用一个*.xml
来表示的,那么,我们当然可以根据SVG
的语法,来编写一个xml
文件,通过pathData
属性进行描述,不过这种方式较为繁琐,一般不会采用。
四、Vector
语法
虽然说大多数情况下,我们不会完全手动去编写Vector
的xml
文件,但是,对于Vector
的基本语法还是有必要了解一些的,因为在我们后边谈到的动态Vector
中需要了解对于每个标签有哪些属性可以设置,Vector
包含下面三种标签:
4.1
标签
-
name
:矢量图的名字 -
width, height
:矢量图的固有宽高,通常使用dp
。 -
viewportWidth, viewportHeight
:把矢量图的宽高分成多少个单元,这里的每个单元就对应pathData
中的一个点坐标。
4.2
标签
-
name
:路径的名称。 -
fillColor
:图形的填充颜色。 -
pathData
:定义控制点的位置,类似与Canvas
当中的Path
类。
4.3
标签
用来把多个
组合在一起,进行相同的处理。
更多的属性可以查阅下面这两篇文章:
VectorDrawable 详解
Android 中的 SVG 图像的各个属性意义
五、Vector
的兼容性问题
为了让VectorDrawable
能够在Android 5.0
以下版本的手机上使用,我们需要引入support
包,并修改gradle
的配置。
5.1 引入support
包
VectorDrawable
是在Android 5.0
之后提出来的,因此,如果我们需要在低版本上使用,那么就要引入com.android.support:appcompat-v7
包,要求版本号大于等于23.2.0
,这里我们选用的是:
compile 'com.android.support:appcompat-v7:25.3.1'
与Vector
相关的两个包为:
5.2 修改gradle
配置文件
如果gradle
的版本小于2.0
:
android {
defaultConfig {
generatedDensities = []
}
aaptOptions {
additionalParameters "--no-version-vectors"
}
}
如果gradle
的版本大于2.0
,例如我们所用的版本:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
}
}
那么需要这样配置:
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
关于更多兼容性的问题,可以查看下面这篇文章
Android Vector 曲折的兼容之路
六、静态VectorDrawable
如果使用静态的方式展示VectorDrawable
,那么很简单,只需要像使用普通的drawable
一样,首先,我们按照第三节的方法,获取到一个vectorDrawable
,并把它放在drawable
文件夹下:
我们可以应用于:
-
ImageView
的src
-
View
的background
-
TextView
的drawable
在上面的例子中,我们还使用了ic_account_circle_selector
,其定义如下:
ic_account_circle_black_24dp
就是之前获取到的素材,而ic_account_circle_black_normal_24dp
就是改变了它的fillColor
属性:
点击后的效果为:
七、动态VectorDrawable
动态的VectorDrawable
,也就是AnimatedVectorDrawable
,一般来说,它的整个结构如下图所示:
为了实现动态的
VectorDrawable
,一般需要提供三种类型的
*.xml
文件,这三个
xml
文件的根标签分别为:
-
vector
:图像资源,也就是我们上面讨论的静态vector
,定义于res/drawable
文件夹下。 -
objectAnimator
:定义图像资源中个元素的动画行为,定义于res/anim
文件夹下。 -
animated - vector
:对vector
中的元素与objectAnimator
进行组合,定义于res/drawable
文件夹下。
7.1 对
标签进行动画
下面,我们先看一个简单的例子,上面我们所谈到的三个*.xml
文件如下:
7.1.1 vector
文件
这里我们生成了一个头像的Vector
素材,它的图像如下,注意到,我们用一个group
标签把path
标签包裹起来,并且给它定义了一个name
属性为group_account
,这个属性在后面会用到。
7.1.2 objectAnimator
文件
objectAnimator
的定义和属性动画是相同的,我们需要指定需要变换的属性,也就是propertyName
,并通过valueFrom/valueTo
指定变化的起点值和终点值,这里我们选择了采用无限循环的方式来变换目标的rotation
属性。
7.1.3 animated-vector
文件
animated-vector
和vector
是一一对应的关系,因此需要在根标签中指定android:drawable
,也就是在7.1.1
中的vector
文件。
而每一个target
标签是内是成对的name - animation
属性,name
就是在7.1.1
中声明的group
的name
,而animation
则是在7.1.2
中定义的动画文件。
如果objectAnimator
所指定的属性在name
所对应的标签中没有,那么不会发生任何变化。
7.1.4 启动动画
首先,在布局的xml
文件中,把imageView
的src
指定为7.1.3
中的animate-vector
:
在代码中,需要手动获得这个vectorDrawable
,然后启动动画:
public class VectorDrawableActivity extends AppCompatActivity {
private ImageView mAnimateView;
private AnimatedVectorDrawable mAnimatedVectorDrawable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_vector_drawable);
mAnimateView = (ImageView) findViewById(R.id.iv_dynamic);
mAnimatedVectorDrawable = (AnimatedVectorDrawable) mAnimateView.getDrawable();
mAnimateView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mAnimatedVectorDrawable.start();
}
});
}
}
效果如下:
7.2 对
标签中的属性进行动画
在7.1
中,演示了如何对group
标签的属性进行变换,下面,我们再演示一下如何对path
标签中的属性进行变换。和前面类似,我们依然需要三种类性的*.xml
文件
7.2.1 vector
文件
这里,同样需要给path
指定一个名字,用于后面和objectAnimator
进行关联,它的素材为:
7.2.2 objectAnimator
文件
这里,我们选择的是path
标签下的trimPathEnd
属性,它表示从Path
终点的位置去除Path
,与之对应的还有trimPathStart
属性,它表示从Path
起点的位置去除Path
,而trimPathOffset
则可以改变Path
的起点,这三个值的取值范围都是0~1
。
7.2.3 animated-vector
文件
效果如下:
7.3
之间切换
除了上面普通的属性之外,还支持对
标签下的
进行改变,系统会比较两个pathData
之间的差别,并自动产生合适的动画。需要注意,它要求这两个pathData
的点坐标的个数是相同的。
7.3.1 Vector
文件
这里,我们需要生成两个vectorDrawable
,首先是起始的VectorDrawable
:
它的素材为:
接着是终点的
VectorDrawable
:
它对应的素材为:
7.3.2 objectAnimator
文件
这里的propertyName
和valueType
需要分别定义为pathData
和pathType
,而起点和终点的值就是我们在7.3.1
生成的两个VectorDrawable
所对应的pathData
属性的值。
7.3.3 animated-vector
文件
最终的效果为:
八、VectorDrawable
的性能
关于VectorDrawable
的性能问题,Android Vector 曲折的兼容之路 这篇文章说的很好,因此直接引用过来了:
Bitmap
的绘制效率并不一定会比Vector
高,它们有一定的平衡点,当Vector
比较简单时,其效率是一定比Bitmap
高的,所以,为了保证Vector
的高效率,Vector
需要更加简单,PathData
更加标准、精简,当Vector
图像变得非常复杂时,就需要使用Bitmap
来代替了。
-
Vector
适用于ICON
、Button
、ImageView
的图标等小的ICON
,或者是需要的动画效果,由于Bitmap
在GPU
中有缓存功能,而Vector
并没有,所以Vector
图像不能做频繁的重绘 -
Vector
图像过于复杂时,不仅仅要注意绘制效率,初始化效率也是需要考虑的重要因素 -
SVG
加载速度会快于PNG
,但渲染速度会慢于PNG
,毕竟PNG
有硬件加速,但平均下来,加载速度的提升弥补了绘制的速度缺陷。
九、参考文献
1. Android Vector 曲折的兼容之路
2. VectorDrawable 怎么玩
3. Android 使用矢量图(SVG, VectorDrawable)实践篇
4. SVG - 百度百科
5. Android 中的 SVG 图像的各个属性意义