Android矢量图动画特效,Android矢量动画实践

4707a4738a51

之前的文章里,有朋友评论说饿了么的动画是使用AnimatedVectorDrawable来实现的。这个东西虽然原来也知道,但是一直没有切实的使用过。刚好昨天有看到一个蛮帅的矢量动画(文末福利),有了兴趣,特意来抽空撸了一个demo来体验下。

先来看看一些我撸的一些demo(部分svg资源及动画搜集自网络)。

4707a4738a51

2017-08-17_21-26-00.gif

效果不错对不对,不仅如此,这些效果完全使用资源文件即可完成,java代码里只要简单的startAnimator即可。通过网络资源撸出了这些效果之后,要开始系统的认知一下了。

SVG 和 VectorDrawable,AnimatedVectorDrawable

相较我们通常使用的png,jpg等格式的位图(Bitmap),SVG拥有体积相对较小,通过描述的形式记录形状,因此可以适应各种大小分辨率而不会失真。

而在Android中,我们不能直接使用原始的 .svg 格式图片,而是需要将其转化为 VectorDrawable,可以理解为一个XML格式的svg文件,即矢量图形在android中的原始资源。

如果只是单纯的运用VectorDrawable,似乎作用就只有缩小apk资源文件体积了,还要考虑svg运行时才计算所造成的额外cpu消耗(将形状描述转化为图形)。但是有了AnimatedVectorDrawable之后,就完全不一样了。

AnimatedVectorDrawable通过ObjectAnimator属性动画控制VectorDrawable,利用矢量图形的特性,从而达成各种炫酷的动画效果。

4707a4738a51

略丑的关系图

通过上述撸的Demo,我大概把它的主要动画效果分为以下三种。

1.两个图形之间的无缝切换。

4707a4738a51

2.按路径绘制图像。

4707a4738a51

3.分组控制图像不同部分。

4707a4738a51

而以上三种特性又可以互相组合,搭配其他的属性动画,实现更复杂的效果。

图三的机器人实际上就是控制了头部和手臂进行y轴的平移动画,而这头,手,身体是属于同一张SVG图片。Demo中前两个案例也是在切换动画的同时配合了旋转的属性动画。

VectorDrawable的格式

我们先比较一下小机器人矢量图的SVG代码和其VectorDrawable代码。

SVG源码

width="500px" height="500px" viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve">

作为VectorDrawable

android:viewportWidth="500"

android:viewportHeight="500"

android:width="500px"

android:height="500px">

android:name="head"

android:fillColor="#9FBF3B"

android:pathData="M301.314,83.298l20.159-29.272c1.197-1.74,0.899-4.024-0.666-5.104c-1.563-1.074-3.805-0.543-4.993,1.199L294.863,80.53c-13.807-5.439-29.139-8.47-45.299-8.47c-16.16,0-31.496,3.028-45.302,8.47l-20.948-30.41c-1.201-1.74-3.439-2.273-5.003-1.199c-1.564,1.077-1.861,3.362-0.664,5.104l20.166,29.272c-32.063,14.916-54.548,43.26-57.413,76.34h218.316C355.861,126.557,333.375,98.214,301.314,83.298" />

android:name="left_eye"

android:fillColor="#FFFFFF"

android:pathData="M203.956,129.438c-6.673,0-12.08-5.407-12.08-12.079c0-6.671,5.404-12.08,12.08-12.08c6.668,0,12.073,5.407,12.073,12.08C216.03,124.03,210.624,129.438,203.956,129.438" />

android:name="right_eye"

android:fillColor="#FFFFFF"

android:pathData="M295.161,129.438c-6.668,0-12.074-5.407-12.074-12.079c0-6.673,5.406-12.08,12.074-12.08c6.675,0,12.079,5.409,12.079,12.08C307.24,124.03,301.834,129.438,295.161,129.438" />

android:name="left_arm"

android:fillColor="#9FBF3B"

android:pathData="M126.383,297.598c0,13.45-10.904,24.354-24.355,24.354l0,0c-13.45,0-24.354-10.904-24.354-24.354V199.09c0-13.45,10.904-24.354,24.354-24.354l0,0c13.451,0,24.355,10.904,24.355,24.354V297.598z" />

android:name="right_arm"

android:fillColor="#9FBF3B"

android:pathData="M372.734,297.598c0,13.45,10.903,24.354,24.354,24.354l0,0c13.45,0,24.354-10.904,24.354-24.354V199.09c0-13.45-10.904-24.354-24.354-24.354l0,0c-13.451,0-24.354,10.904-24.354,24.354V297.598z" />

android:name="body"

android:fillColor="#9FBF3B"

android:pathData="M140.396,175.489v177.915c0,10.566,8.566,19.133,19.135,19.133h22.633v54.744c0,13.451,10.903,24.354,24.354,24.354c13.451,0,24.355-10.903,24.355-24.354v-54.744h37.371v54.744c0,13.451,10.902,24.354,24.354,24.354s24.354-10.903,24.354-24.354v-54.744h22.633c10.569,0,19.137-8.562,19.137-19.133V175.489H140.396z" />

我们明显能看到一些共通的标签。类似 width,height, g 和 group,path等。

其中svg源码中标签比较多,我们不需要去关心。SVG最重要的一部分,就是其中的path——路径了。

之前提到过svg是通过描述形状来记录图形,即path。玩过画笔的都了解吧,从一个点画到另一个点。而宽高则标识了画布的大小,我们路径的坐标应该在相应的宽高之内,超出去就看不到了。

通常Path是一个完整的路径。机器人中,有手臂,身体等不同的部分,因此也就有了多个Path来描述。这个VectorDrawable中给各部分都命名并分组,看起来是很清楚的。而通常简单的形状使用一个Path即可描述。

因此,只要有了对应的Path,我们就能把一个SVG图像转化为Android可用的VectorDrawable了。

让VectorDrawable动起来

以demo中的第一个效果为例。

先看看它的XML中组成。

android:layout_width="200dp"

android:layout_height="200dp"

android:onClick="btnClick"

android:src="@drawable/animated_play_pause"

android:background="@color/colorPrimary"

android:layout_marginTop="20dp"

/>

ImageView引用的图片资源为 animated_play_pause

android:drawable="@drawable/vector_play">

android:animation="@animator/animator_play_pause"

android:name="play"/>

android:animation="@animator/animator_rotate"

android:name="playgroup"/>

这个就是传说中的 AnimatedVectorDrawablele。这个XML中,首先用drawable标签声明了一个默认显示的VectorDrawable对象 vector_play,这个是我们的矢量播放键。

其中定义了两个target目标,有两个参数,分别是animation,和name,前者定义了使用的动画效果,后者则是动画效果针对的目标对象。这个name必须与VectorDrawable对象的path和group声明的name相同,否则在开始动画时会找不到对象而报错。

两个动画

android:duration="500"

android:valueType="pathType"

android:propertyName="pathData"

android:valueFrom="M 3,2 L 7,5 L7,5 L3,5z M 3,8 L7,5 L7,5 L3,5z"

android:valueTo="M 2,2 L 8,2 L8,4 L2,4z M 2,8 L8,8 L8,6 L2,6z"

/>

android:duration="1000"

android:propertyName="rotation"

android:valueType="floatType"

android:valueFrom="0"

android:valueTo="-90"/>

第一个就是从播放键切换到暂停键的动画了,和使用普通的属性动画一样,只不过valueType和propertyName分别为pathType,pathData,表明动画针对路径变化。

是的,矢量动画的切换效果只是从一个形状的路径切换到另外一个路径而已。

ValueFrom的参数实际上就是播放键的路径参数,valueTo是暂停键路径。

旋转动画就不多讲了,不过一个需要注意的点是,在target中的两个name是不同的。其中 play 是 path 的name,而 palygroup则是path所在group的name。

android:width="100dp"

android:height="100dp"

android:viewportHeight="10"

android:viewportWidth="10">

android:name="playgroup"

android:pivotX="5"

android:pivotY="5">

android:name="play"

android:fillColor="#fff"

android:pathData="M 3,2 L 7,5 L7,5 L3,5z M 3,8 L7,5 L7,5 L3,5z"/>

在使用时,我们不能直接针对Path使用例如旋转平移等属性动画,而是要将目标定位包裹path的group,否则会出现如下错误。FullPath不支持的动画属性。

4707a4738a51

这样,我们一个形状变化加旋转的AnimatedVectorDrawable就完成了,点击触发动画,在java中如下:

public void btnClick(View view) {

ImageView imageView = (ImageView) view;

Drawable drawable = imageView.getDrawable();

if (drawable instanceof Animatable) {

((Animatable) drawable).start();

}

}

补充1 路径绘制

与变换动画对应的还有一个绘制路径的动画。实际上也相当简单,是指将对应的参数变为了trimPathEnd,值得变化是0到1,代表完全绘制。以上都是些比较基础的运用,可以下载文末我的Demo获取完整的svg资源,自己尝试。

android:propertyName="trimPathEnd"

android:valueFrom="0"

android:valueTo="1"

android:duration="5000"

android:valueType="floatType"

android:interpolator="@android:interpolator/linear"/>

补充 2 animated-selector 多个animator-vector集合。

当我们使用animator_vector时,不论是绘制路劲还是形状切换,都是只有from to两个状态,那么在我们切换完成之后呢,如果想要继续切换第三个路径,或者是切换回去,这时候就需要用到animator-selector。

类似于选择器,通过不同的状态来执行不同的animator-vector,从而达到在几个不同路径的来回切换效果。如同demo中的爱心与twitter来回切换效果。

4707a4738a51

demo中searchbar,则是结合trimPath的效果。

4707a4738a51

补充 3 Path语法

上述代码中有列出许多Path,虽然我们并不需要手动计算矢量图的路径,但是还是需要清除相关的含义。

M: move to 移动绘制起点(Mx,y)

L:line to 直线画到点(Lx,y)

H:横向连线 (Hx)

V:纵向连线 (Vy)

Z:close 闭合首尾无参

C:cubic bezier 三次贝塞尔曲线 (x1,y1,x2,y2)

Q:quatratic bezier 二次贝塞尔曲线(x1,y1,x2,y2,x3,y3)

A: ellipse 圆弧

每个命令都有大小写形式,大写代表后面的参数是绝对坐标,小写表示相对坐标。参数之间用空格或逗号隔开。

感兴趣自己看官方文档,玩死人不偿命系列。

补充 4 关于坐标匹配

实际上并不是任何两个SVG都可以无缝切换,如果想要让两个图形能够合理过渡,开始找了两个图形想要切换时,通常会出现 Can't morph from x to y 的错误。因此必须保持两个路径的格式匹配。

4707a4738a51

image.png

通常软件生成的路径千奇百怪,路径如果复杂了则非常难改。

VectAlign 是github上的一个开源项目,主要功能就是通过计算修改两个SVG的路径使其可以无缝切换。

4707a4738a51

补充 5 一个非常棒的矢量动画库RichPath

效果很棒,在代码中自如的控制Path和属性,比起纯资源文件可操作性更高,

嗯,效果比我的炫酷多了...

4707a4738a51

原谅我盗了一张图

补充 6 关于文末福利

本文Demo完整项目地址

自制矢量动画实践之如何摆脱UI ???....这里

参考内容及部分svg素材来源

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值