自Android 5.0(API 21)开始,Vector drawable(矢量图像)正式得到了支持,可以通过VectorDrawable
和AnimatedVectorDrawable
来实现矢量图像。不过这两个在5.0以上的系统运行,因此为了支持更多5.0以下的系统,我们可以通过导入Android support library的方式并使用VectorDrawableCompat
和AnimatedVectorDrawableCompat
来实现矢量图。
对于API 24及更高版本,AnimatedVectorDrawableCompat
会自动委托给AnimatedVectorDrawable
。 对于API 24之下的版本,此类相当是带有ObjectAnimator
和AnimatorSet
属性的VectorDrawableCompat
,从而创建动画drawable。同理VectorDrawableCompat
也会自动委托给VectorDrawable
。
SVG的全称是Scalable Vector Graphics(可缩放矢量图形),它是专门用于网络的矢量图形标准。与SVG对应的是Bitmap(位图),位图是由一个个像素点组成的,当图片放大到一定的大小时,会出现马赛克现象;而矢量图则是由一个个点组成,结果数学计算利用直线和曲线绘制而成,无论如何方法都不会出现马赛克现象。
SVG相比Bitmap:
标准的SVG语法中支持很多标签,比如rect(绘制矩形)、circle(绘制圆形)、line(绘制线段)、polyline(绘制折现)、ellipse(绘制椭圆)、polygon(绘制多边形)等。
但是Android中并没有对原生的SVG语法进行支持,而是以一种简化的方式对SVG进行兼容。Android是通过使用Path标签实现SVG的图像。虽然较为复杂,但是对于SVG图像的转换Android Studio中提供了Vector Asset Studio工具,可以轻松完成。
Android中的矢量图是VectorDrawable
(平时较多使用VectorDrawableCompat
以兼容更多版本,API 24及以上自动委托给VectorDrawable
),VectorDrawable
是一个在XML文件中定义了一组点、线、曲线、颜色和其他相关信息的矢量图形。其最大的优势便是缩放不失真,这能有效减少APK体积并减少开发人员的维护,而矢量动画就是建立在VectorDrawable
上形成的。
VectorDrawable
以树状结构定义属性,由Path
和Group
组成。Path
用来定义可绘图的路径,Group
则用于定义一系列路径或者将Path
标签分组。Path
绘制顺序与XML文件中显示的顺序相同。它可以使用
元素在XML文件中定义。
在静态图像中,单纯使用一个path标签实现还是使用一组path标签实现没有什么实质性的区别;在动画中,我们可以指定每个path路径做特定的动画,通过group标签则可以将原本由一个path路径实现的内容分为多个path路径来实现,每个path路径可以指定特定的动画,这样一来显示效果就丰富多彩了。
AnimatedVectorDrawable
将动画属性添加到矢量图形中。我们更多的是使用AnimatedVectorDrawableCompat
,其具有更好的兼容性,对于API 24及更高版本,此类会自动委托给AnimatedVectorDrawable
。
同时自API 25开始,AnimatedVectorDrawable
在RenderThread(渲染线程)上运行(而不是如早期API在UI线程上运行),这意味着即使UI线程上有大量负载,动画也能流畅的展现。
定义一个AnimatedVectorDrawable
可以使用三个独立的XML文件,也可以使用一个XML文件。
AnimatedVectorDrawable can be defined in either three separate XML files, or one XML.
通过对VectorDrawable
设置动画属性来实现动画效果。而对于动画将由ObjectAnimator
执行,它的对象可以是根元素,可以是组元素,还可以是路径元素。(The ObjectAnimator’s target can be the root element, a group element or a path element),对于目标元素,他们要求是不重名的,而没有动画的元素则可以不命名。
以下是VectorDrawable
的动画属性:
元素 | 动画属性 | 说明 |
---|---|---|
|
alpha | Drawable的透明度,默认为1.0(即不透明) |
|
rotation | 定义该组图像的旋转度数 |
pivotX | 定义该组缩放和旋转时的X参考点 | |
pivotY | 定义该组缩放和旋转时的Y参考点 | |
scaleX | 定义该组X轴缩放大小 | |
scaleY | 定义该组Y轴缩放大小 | |
translateX | 定义该组沿X轴平移的距离 | |
translateY | 定义该组沿Y轴平移的距离 | |
|
pathData | 对SVG矢量图的描述 |
fillAlpha | 填充颜色的透明度 | |
fillColor | 填充颜色 | |
strokeColor | 描边颜色 | |
strokeWidth | 描边宽度 | |
strokeAlpha | 描边透明度 | |
trimPathStart | 指定路径从哪里开始 | |
trimPathEnd | 指定路径在哪里结束 | |
trimPathOffset | 指定路径的位移距离 | |
strokeLineCap | 描边线条重点形状(线帽):butt(无线帽)、round(圆形)、square(方形) |
其中,对于pathData有很多指令:
M x,y
)=moveto:将画笔移动到指定的坐标位置L x,y
)=lineto:画直线到指定的坐标位置H x
)=horizontal lineto:画水平线到指定的X坐标位置V y
)=vertical lineto:画垂直线到指定的Y坐标位置C x1,y1,x2,y2,endx,endy
)=curveto:三阶贝塞尔曲线S x2,y2,endx,endy
)=smooth curveto:根据上一个指令终点最为起点的三阶贝塞尔曲线Q x,y,endx,endy
)=quadratic Belzier curve:二阶贝塞尔曲线T endx,endy
)=smooth quadratic Belzier curve:根据上一个指令终点最为起点的二阶贝塞尔曲线A rx,ry,xRotation,flag1,flag2,x,y
)=elliptical Arc:弧线
注意:
- 坐标轴以(0,0)点为中心,X轴水平向右,Y轴水平向下
- 所有指令大小写皆可,但是大写表示绝对定位,参照全局坐标系;小写表示相对定位,参照父容器坐标系
- 指令和数据间的空格可以省略
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportHeight="600"
android:viewportWidth="600" >
<group
android:name="rotationGroup"
android:pivotX="300.0"
android:pivotY="300.0"
android:rotation="45.0" >
<path
android:name="v"
android:fillColor="#000000"
android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
group>
vector>
组成一个AnimatedVectorDrawable
通常包含一个VectorDrawable
和一个或多个目标元素。 对于目标元素可以通过android:name
指定其目标,并通过android:animation
将该目标与其对应的动画元素(ObjectAnimator
或AnimatorSet
)进行连接。
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/vectordrawable" >
<target
android:name="rotationGroup"
android:animation="@animator/rotation" />
<target
android:name="v"
android:animation="@animator/path_morph" />
animated-vector>
这个XML文件是目标元素的动画效果。例如上面的rotation.xml和path_morph.xml。
rotation.xml通过objectAnimator
定义的是在6000毫秒内旋转360度:
<objectAnimator
android:duration="6000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360" />
path_morph.xml则将path从一个形状变换为另一个形状。
对于Path变换必须与之前的形状兼容,也就是说形状相同,顺序相同,并且路径中的变化命令也需要相同。
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="3000"
android:propertyName="pathData"
android:valueFrom="M300,70 l 0,-70 70,70 0,0 -70,70z"
android:valueTo="M300,70 l 0,-70 70,0 0,140 -70,0 z"
android:valueType="pathType"/>
set>
由于AAPT工具支持将几个相关XML文件捆绑在一起的新格式,我们可以将之前示例中的XML文件合并到一个XML文件中:
<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:height="64dp"
android:width="64dp"
android:viewportHeight="600"
android:viewportWidth="600" >
<group
android:name="rotationGroup"
android:pivotX="300.0"
android:pivotY="300.0"
android:rotation="45.0" >
<path
android:name="v"
android:fillColor="#000000"
android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
group>
vector>
aapt:attr>
<target android:name="rotationGroup">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="6000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360" />
aapt:attr>
target>
<target android:name="v" >
<aapt:attr name="android:animation">
<set>
<objectAnimator
android:duration="3000"
android:propertyName="pathData"
android:valueFrom="M300,70 l 0,-70 70,70 0,0 -70,70z"
android:valueTo="M300,70 l 0,-70 70,0 0,140 -70,0 z"
android:valueType="pathType"/>
set>
aapt:attr>
target>
animated-vector>
为了能够支持在低于Android 5.0(API 21)的设备上绘制矢量图像和矢量动画,可以使用VectorDrawableCompat
和AnimatedVectorDrawableCompat
,它们分别通过两个库来提供支持:support-vector-drawable
和animated-vector-drawable
(包含在com.android.support:appcompat兼容包中)。
做法:
引用com.android.support:appcompat-v7:23.4.0
及以上的版本
引入对于VectorDrawable
的支持:
对于Gradle Plugin 2.0以上:
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
对于Gradle Plugin 1.5及以下:
android {
defaultConfig {
// Stops the Gradle plugin’s automatic rasterization of vectors
generatedDensities = []
}
// Flag notifies aapt to keep the attribute IDs around
aaptOptions {
additionalParameters "--no-version-vectors"
}
}
兼容包对以下内容是不支持的:
- Path Morphing:路径变化动画
- Path Interpolation:路径差值器(只能使用系统差值器)
对于ImageView
、ImageButton
、FloatingActionButton
等可以使用app:srcCompat
来指定矢量动画,并在使用到这个ImageView
等的地方获取drawable,然后start。
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_add" />
(imageview as AnimatedVectorDrawableCompat).Drawable.start()
还可以通过setImageResource()的方式动态设置。
animatedVectorDrawableCompat = AnimatedVectorDrawableCompat.create(context!!, R.drawable.animated_splash_logo)
imageView.apply {
setImageDrawable(animatedVectorDrawableCompat)
}
animatedVectorDrawableCompat?.start()
Button并不能直接通过app:srcCompat
属性来使用,需要通过selector标签来使用。同时在使用时需要将下面的代码放在Activity的前面。
static {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
由于在23.2.0中的兼容包中存在问题,23.4.0修复了问题,但为了区分旧版本其添加了一个标签,这个标签需要我们手动打开,而这里的static就是为了打开该标签。