在完成矢量图动画之前,必须了解矢量图在Android中的代码表示。Android Studio也可以制作自带的矢量图,或者导入svg格式的图片生成矢量图的代码。
我在Android Studio神器之Vector Asset这篇文章上已经做了简单的介绍。其中最为关键之处就是看懂矢量图的代码了。
(1)使用Vector Asset工具随意生成一个矢量图代码
矢量图的代码如下:
图像如下:
以上是使用Vector Asset工具生成的矢量图和矢量图代码。
android:width
:表示是矢量图的宽度;
android:height
:表示矢量图的高度;
android:viewportWidth
:表示将矢量图的宽分成N等分,这里是分成24等分;
android:viewportHeight
:表示将矢量图的高分成N等分,这里是分成24等分;
:表示一个路径
android:pathData
:表示路径上的数据
名称 | 解释 |
---|---|
M = moveto(M X,Y) | 将画笔移动到指定的坐标位置 |
L = lineto(L X,Y) | 画直线到指定的坐标位置 |
H = horizontal lineto(H X) | 画水平线到指定的X坐标位置 |
V = vertical lineto(V Y) | 画垂直线到指定的Y坐标位置 |
C = curveto(C X1,Y1,X2,Y2,ENDX,ENDY) | 三次贝赛曲线 |
S = smooth curveto(S X2,Y2,ENDX,ENDY) | 同样三次贝塞尔曲线,更平滑 |
Q = quadratic Belzier curve(Q X,Y,ENDX,ENDY) | 二次贝赛曲线 |
T = smooth quadratic Belzier curveto(T ENDX,ENDY) | 同样二次贝塞尔曲线,更平滑 |
A = elliptical Arc(A RX,RY,XROTATION,large-arc-flag,sweep-flag,X,Y) | 弧线 |
Z = closepath() | 关闭路径 |
以上所有命令均允许小写字母。大写的字母是基于原点的坐标系(偏移量),即绝对位置;小写字母是基于当前点坐标系(偏移量),即相对位置。
(2)自己绘制一个矢量图
按照上面说到的path命令,我们完全可以自己绘制一个简单的矢量图
这是一条直线,如图:
然而,更加复杂的矢量图绘制难度很大。
我们完全可以利用绘图工具制作一个SVG图片,然后使用AS生成代码,也可以使用AS自带的Vector Asset工具制作SVG图片。
然后,复杂的SVG生成的代码必然也是更加的复杂,这样就必须加深SVG的了解了。
(3)必须了解的API:VectorDrawable
VectorDrawable 一般是以
为根标签定义的 XML 文件,
标签下还可以有三种标签,分别是:
、
、
,下面分别贴出这几种标签对应的属性。
定义这个矢量图 | |
---|---|
android:name | 矢量图的名字 |
android:width | 矢量图的内部(intrinsic)宽度,支持所有Android系统支持的尺寸,通常使用dp |
android:height | 矢量图的内部(intrinsic)高度 |
android:viewportWidth | 矢量图视图的宽度,视图就是矢量图path路径数据所绘制的虚拟画布 |
android:viewportHeight | 矢量图视图的高度 |
android:tint | 矢量图的tint颜色。默认是没有tint颜色的 |
android:tintMode | 矢量图tint颜色的Porter-Duff混合模式,默认值为src_in。(src_in,src_over,src_atop,add,screen,multiply) |
android:autoMirrored | 设置当系统为RTL(right-to-left)布局的时候,是否自动镜像该图片。比如阿拉伯语 |
android:alpha | 该图片的透明度属性 |
设置路径做动画的关键属性的 | |
---|---|
android:name | 定义group的名字 |
android:rotation | 定义该group的路径旋转多少度 |
android:pivotX | 定义缩放和旋转该group时候的X参考点。该值相对于vector的viewport值来指定的。 |
android:pivotY | 定义缩放和旋转该 group 时候的Y参考点。该值相对于vector的viewport值来指定的。 |
android:scaleX | 定义X轴的缩放倍数 |
android:scaleY | 定义Y轴的缩放倍数 |
android:translateX | 定义移动X轴的位移。相对于vector的viewport值来指定的。 |
android:translateY | 定义移动Y轴的位移。相对于vector的viewport值来指定的 |
路径 | |
---|---|
android:name | 定义该path的名字,这样在其他地方可以通过名字来引用这个路径 |
android:pathData | 和SVG中d元素一样的路径信息。 |
android:fillColor | 定义填充路径的颜色,如果没有定义则不填充路径 |
android:strokeColor | 定义如何绘制路径边框,如果没有定义则不显示边框 |
android:strokeWidth | 定义路径边框的粗细尺寸 |
android:strokeAlpha | 定义路径边框的透明度 |
android:fillAlpha | 定义填充路径颜色的透明度 |
android:trimPathStart | 从路径起始位置截断路径的比率,取值范围从0到1;注意从一半到起始动画为from-0.5-to-0 |
android:trimPathEnd | 从路径结束位置截断路径的比率,取值范围从0到1;注意从一半到结束动画为from-0.5-to-1.0 |
android:trimPathOffset | 设置路径截取的范围,取值范围从0到1 |
android:strokeLineCap | 设置路径线帽的形状,取值为 butt, round, square. |
android:strokeLineJoin | 设置路径交界处的连接方式,取值为 miter,round,bevel. |
android:strokeMiterLimit | 设置斜角的上限 |
定义当前绘制的剪切路径。注意,clip-path 只对当前的 group 和子 group 有效 | |
---|---|
android:name | 定义clip-path的名字 |
android:pathData | android:pathData的取值一样。 |
查看以上标签属性,我们发现
标签其实是为动画存在的,它本身对矢量图的绘制关系不大,而这个动画叫做矢量图动画
。
那么,这个动画到底怎么实现呢?这里还需要了解一个接口:AnimatedVectorDrawable
(4)必须了解的API:AnimatedVectorDrawable
一般情况,表示一张矢量图不需要group
标签,但是如果涉及到动画的话,可能就需要将一个或者多个路径进行分组。
AnimatedVectorDrawable通过ObjectAnimator
或AnimatorSet
对VectorDrawable的某个属性作一个矢量资源的动画。
AnimatedVectorDrawable就是矢量图动画,完成矢量图动画的要素有三,如下:
- 一张矢量图,即以vector为标签的xml文件
- 一个动画,objectAnimator或者AnimatorSet
- AnimatedVectorDrawable,即以animated-vector为标签的xml文件
【举例】
实现左右箭头移动
[第一步]
选择并自动生成一张矢量图
生成的矢量图代码如下:
[第二步]
拆分矢量图的两个箭头
矢量图的路径一般以Z(z)为结尾,根据这个特性,将矢量图拆分,拆分后的代码如下:
[第三步]
准备好左右移动的动画
anim_left.xml
anim_right.xml
[第四步]
animated-vector编写
其中,ic_swap_horiz_black_24dp
为矢量图,animation为某动画,name和矢量图group标签的name对应。
[第五步]
设置src
这里需要注意的是,如果设置background
动画是无效的,需要设置src
才有动画效果。
[第六步]
在代码中执行动画
case R.id.button:
Drawable drawable = ((ImageView)findViewById(R.id.imageview)).getDrawable();
if (drawable instanceof Animatable){
((Animatable)drawable).start();
}
break;
但是,我们发现,完成一个矢量图动画需要建立多个xml文件,为了解决这个问题,可以将矢量图所用到的xml合并。
合并之后的xml如下:
使用时,只要直接设置src并且执行动画即可。
Drawable drawable = ((ImageView)findViewById(R.id.imageview)).getDrawable();
if (drawable instanceof Animatable){
((Animatable)drawable).start();
}
(5)Shape Shifter工具的基本使用
[第一步]
打开网页在线编辑
https://shapeshifter.design/
[第二步]
文件导入
在本地选择一个SVG格式的矢量图
或者Vector Drawble
,如下:
导入之后的图片如下:
[第三步]
查看文件
点击图中的path,可以查看路径代码
我们可以对这个路径进行修改,比如修改颜色
再看,图中的网状线条,其实就是给矢量图分成了24等份方便坐标表示,这里的pathData就是根据坐标绘制轨迹的。
[第四步]
设置动画时长
默认时长为300ms,点击修改动画时长为1秒。
[第五步]
考虑好自己想要完成的动画,比如让整个图片进行旋转
结合group标签的知识,group标签的功能有:设置锚点、旋转、缩放、平移。
所以这里的旋转动画可以使用group标签来完成。
[第六步]
添加group标签,并将path添加到group标签中
点击图中的“+”,添加一个group图层
并将path拖入group中
[第七步]
为group添加旋转动画
如图,修改group的初始值,将锚点调整到图片中央(图片分成了24等份)
点击右上角的“闹钟”图标,添加“rotation”字段
在时间线区域不自动生成一个绿色时间线,正好与字段“rotation”字段平行,选中绿色时间线,绿色时间线变为蓝色时间线,在屏幕右上角出现该时间线的属性:
startTime:开始时间
endTime:结束时间
interpolator:动画插值器
fromValue:动画的初始旋转角度
toValue:动画的结束旋转角度
将动画时间改为1000ms,任意选择动画插值器,将动画角度变化范围调整为0~360度。
[第八步]
播放动画
[第九步]
导出矢量图动画文件
最后,直接导出文件即可,点击Export-->Animated Vector Drawable。
生成的代码如下:
设置这个矢量图动画
最后再代码中播放动画
Drawable drawable = ((ImageView)findViewById(R.id.imageview)).getDrawable();
if (drawable instanceof Animatable){
((Animatable)drawable).start();
}
演示效果如下:
(6)Shape Shifter工具的Group属性
group标签除了旋转动画之外以,还有pivotX、pivotY、scaleX、scaleY、translateX、translateY等属性可以设置动态变化。
下面来一一举例:
[pivotX]
和[pivotY]
:设置锚点
上面图形的旋转动画的锚点的取值是(12,12),这个值从动画开始到动画结束没有发生变化,下面将锚点也随着时间动画变化呢?
[scaleX]
和[scaleY]
:动态缩放
[translateX]
和[translateY]
:动态平移
【略】
(7)Shape Shifter工具的Path属性
可被设置动画的字段有,pathData、fillColor、fillAlpha、strokeColor、strokeAlpha、strokeWidth、trimPathStart、trimPathEnd、trimPathOffset。
pathData:
和SVG中d元素一样的路径信息,可以将路径设置为动画开始和结束的取值;
【略】
fillColor:
定义填充路径的颜色,如果没有定义则不填充路径
fillAlpha:
定义填充路径颜色的透明度
strokeColor:
定义如何绘制路径边框,如果没有定义则不显示边框
strokeAlpha:
定义路径边框的透明度
【略】
strokeWidth:
定义路径边框的粗细尺寸
【略】
trimPathStart:
从路径起始位置截断路径的比率,取值范围从0到1;
这里需要注意的是,截断的是路径,而非填充色,上图的路径加上了边框,这个边框就是轨迹。
trimPathEnd:
从路径结束位置截断路径的比率,取值范围从0到1;
这里需要注意的是,截断的是路径,而非填充色,上图的路径加上了边框,这个边框就是轨迹。
trimPathOffset:
设置起点路径和终点路径偏移量的范围,取值范围从0到1
这里需要注意的是,截断的是路径,而非填充色,上图的路径加上了边框,这个边框就是轨迹。
(8)Shape Shifter工具自带Demo解析
[Demo:Play to Pause]
如图所示,完成这个动画需要两个字段的动画:rotation、pathData
旋转动画的字段在group标签上,取值范围是0~90度。
路径动画的字段在path标签上,去世范围是:从M 8 5 L 8 12 L 19 12 L 19 12 L 8 5 M 8 12 L 8 19 L 19 12 L 19 12 L 8 12到M 5 6 L 5 10 L 19 10 L 19 6 L 5 6 M 5 14 L 5 18 L 19 18 L 19 14 L 5 14。
在右上角有一个编辑按钮,点击进入编辑界面
编辑界面顶部有几个按钮:
加号按钮的作用是添加一个点
;
剪刀按钮的作用是画一条直线分割一个路径,使路径一分为二
;
双向箭头按钮的作用是匹配动画前后的路径
;
双向箭头后面的按钮的作用是将选中的路径上的点反转
,动画前后的点必须一一对应,路径上的点反转之后动画也会发生改变;
左箭头按钮的作用是将路径的点依次向上移动一个单位
;
右箭头按钮的作用是将路径的点依次向下移动一个单位
;
总之,为了将两个毫不相关的路径完成动画效果,必须将两个路径紧密的联系在一起,这个编辑界面可以将两个毫不相关的路径紧密的联系在一起,最终完成动画。
代码如下:
接下来的几个Demo将直接贴出动画效果和代码。
[Demo:Search to Close]
动画效果如下:
代码如下:
[Demo:Morphing animals]
动画效果如下:
代码如下:
[Demo:Visibility strike]
动画效果如下:
代码如下:
[Demo:Heart break]
动画效果如下:
代码如下:
[本章完...]