一、概述

相较于png、jpg等位图通过存储像素点来记录图像,svg (Scalable Vector Graphics)拥有一套自己的语法,通过描述的形式来记录图形。Android并不直接使用原始的svg格式图片,而是将其转化为VectorDrawable。VectorDrawable是一个xml格式的drawable,是矢量图在Android中的原始资源,引用方法和png、jpg等其他drawable一样。但是,VectorDrawable仍然只是一个静态图片,和png、jpg等没什么区别,如果想让VectorDrawable “动”起来,就需要用到AnimatedVectorDrawable。AnimatedVectorDrawable才是真正的矢量动效图,其原理就是把VectorDrawable和ObjectAnimator结合起来,通过ObjectAnimator属性动画控制VectorDrawable,利用矢量图形的特性,从而达到各种炫酷的效果。


二、开发流程

我们下面以一个解锁动效为例,来讲解矢量图动效开发的整个流程。

(1)svg到VectorDrawable

svg源文件由美工制作(Sketch、AI等工具均可输出svg),VectorDrawable也可以通过svg2android工具直接由svg转化而来。

网址:http://inloop.github.io/svg2android/

工具:svg2android-gh-pages.zip

本示例我们需要一个锁的矢量图ic_lock_32dp

  <?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportHeight="110"
android:viewportWidth="110"> <group
android:name="g_lock_arc"
android:pivotX="38"
android:scaleX="1.0">
<path
android:name="lock_arc"
android:pathData="M71.6,29v-5.4c0-8.9-7.6-16-17-16s-17,7.2-17,16V29"
android:strokeColor="#000000"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:strokeWidth="4" />
</group> <path
android:name="lock_rect"
android:pathData="M39,29h32c5.5,0,10,4.5,10,10v32c0,5.5-4.5,10-10,10H39c-5.5,0-10-4.5-10-10V39C29,33.5,33.5,29,39,29z"
android:strokeColor="#000000"
android:strokeWidth="4" />
</vector>

矢量图主要是由path和group组成,矢量动画实际上就是通过控制path和group的属性变化来实现动画效果的。

(2)VectorDrawable到AnimatedVectorDrawable

有了矢量图,就可以设计矢量动画了。分析上面的解锁动效,整个解锁过程可拆分为两部分

  1. 上曲线(name="lock_arc")线条收缩
  2. 上曲线组(name="g_lock_arc")整体水平翻转

我们设计矢量动画图avd_lock_to_open如下:

  <?xml version="1.0" encoding="utf-8"?>
<animated-vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ic_lock_32dp" ><!--引用的矢量图-->
<!--曲线收缩-->
<target
android:name="lock_arc"
android:animation="@anim/anim_lock_to_open_p1" />
<!--曲线组翻转-->
<target
android:name="g_lock_arc"
android:animation="@anim/anim_lock_to_open_p2" />
</animated-vector>

分析上面代码

  • android:drawable指定的是我们将对哪个矢量图做动效
  • target标签的android:name指定要对矢量图的哪个部分做动效
  • target标签的android:animation引用一个objectAnimator,指定要对该部分做什么动画

anim_lock_to_open_p1通过控制trimPathStart属性对path(name="lock_arc")做了收缩:

  <?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="300"
android:interpolator="@android:anim/accelerate_interpolator"
android:propertyName="trimPathStart"
android:startOffset="100"
android:valueFrom="0"
android:valueTo="0.24"
android:valueType="floatType"/>
</set>

anim_lock_to_open_p2通过控制scaleX属性对group(name="g_lock_arc")做了水平翻转:

  <?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="400"
android:interpolator="@android:anim/linear_interpolator"
android:propertyName="scaleX"
android:valueFrom="1"
android:valueTo="-1"
android:startOffset="450"
android:valueType="floatType"/>
</set>

通过startOffset可以精确控制两个动画的执行顺序。至此,我们已经写好了AnimatedVectorDrawable。

(3)AnimatedVectorDrawable的使用

AnimatedVectorDrawable本身还是一个drawable,和其他图片的引用方式是一样的。这里我们把它设置给ImageView

  <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/img"
android:layout_gravity="center"
android:layout_width="64dp"
android:layout_height="64dp"
android:src="@drawable/avd_lock_to_open"/>
</FrameLayout>

矢量动态图不会自动播放,在需要播放的时候执行如下代码

  Drawable drawable = mImageView.getDrawable();
if (drawable instanceof Animatable) {
((Animatable) drawable).start();
}

至此,一个矢量动效的开发和引用已经全部完成了。但有时候我们不想每次都主动调用start方法来播放动效,而是希望根据控件的状态(如state_pressed)改变自动播放相应的过渡动效,这时就需要用到animated-selector了。

(4)Animated-Selector用法

在讲解animated-selector之前,我们先看一下selector的用法,它可以根据控件的不同状态显示不同的drawable,如

  <?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 默认时的背景图片 -->
<item android:drawable="@drawable/pic1" />
<!-- 没有焦点时的背景图片 -->
<item android:state_window_focused="false"
android:drawable="@drawable/pic2" />
<!--获得焦点时的图片背景 -->
<item android:state_focused="true"
android:drawable="@drawable/pic3" />
<!--选中时的图片背景 -->
<item android:state_selected="true"
android:drawable="@drawable/pic4" />
</selector>

但使用selector时,状态切换是瞬间完成的,没有过渡。如果希望在状态切换时增加动效,那就需要用到animated-selector。为了讲解,我们仿照矢量动态图avd_lock_to_open再写一个闭锁的动态图avd_open_to_lock。其中会用到一个矢量图ic_open_32dp和两个objectAnimator:anim_open_to_lock_p1、anim_open_to_lock_p2,代码类似,不再展示。我们直接看animated_selector的写法:

  <?xml version="1.0" encoding="utf-8"?>
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/state_on"
android:drawable="@drawable/ic_lock_32dp"
android:state_checked="true" />
<item
android:id="@+id/state_off"
android:drawable="@drawable/ic_open_32dp" />
<transition
android:drawable="@drawable/avd_lock_to_open"
android:fromId="@id/state_on"
android:toId="@id/state_off" />
<transition
android:drawable="@drawable/avd_open_to_lock"
android:fromId="@id/state_off"
android:toId="@id/state_on" />
</animated-selector>

分析上面代码:

  • item标签指定了确定状态下的drawable
  • transition标签指定了状态切换时执行的矢量动效

通常情况下,我们会手动设置控件的状态,以便在适当的时候显示我们想要的动效。比如,我们希望点击ImageView时在两个矢量动效之间切换:

  boolean isChecked = false;
mImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
isChecked = !isChecked;
inal int[] stateSet = {isChecked ? android.R.attr.state_checked : 0};
mImageView.setImageState(stateSet, true);//设置state_checked状态
}
});

使用animated-selector后,我们不再需要主动去调start( )方法来播放动效,只需要设置控件状态即可。

最终效果:

至此,我们已经完成了一套完整的矢量动效开发流程,目录结构如下:

Github源码:https://github.com/JiaxtHome/AnimDemo


三、总结

我们已经知道svg动效实际上就是通过控制path或group的属性变化来达到动画效果,下面列出常用的可控属性

svg可控属性
Name Tags Comment
strokeAlpha path 定义路径边框的透明度
strokeWidth path 定义路径边框的粗细尺寸 
strokeColor path 定义路径边框的颜色 
 fillColor  path  定义填充路径的颜色 
 fillAlpha path 定义填充路径的颜色透明度 
 pathData path 定义路径形状,可用来做morphing动效 
trimPathStart   path  从路径起始位置截断路径的比率,取值范围从 0 到1 
trimPathEnd   path  从路径结束位置截断路径的比率,取值范围从 0 到1 
 trimPathOffset  path  设置路径截取的范围,取值范围从0到1 
rotation  group 定义旋转角度 
pivotX   group  定义缩放和旋转时的 X 参考点,相对于 viewport 值来指定 
pivotY   group  定义缩放和旋转时的 Y 参考点,相对于 viewport 值来指定 
 scaleX  group  定义 X 轴的缩放倍数 
 scaleY group 定义 Y 轴的缩放倍数 
translateX  group 定义 X 轴方向位移,相对于viewport 值来指定 
translateY   group  定义 Y 轴方向位移,相对于viewport 值来指定 

上面属性基本可以分为三类,同时也决定了我们能做的动效类型

(1)改变路径的颜色、尺寸、截断

(2)路径的形状变化

(3)旋转、缩放、平移

其中morphing动画是svg动画的亮点,但并不是任意两个图形之间都能变换,需要图形路径的绘制命令相同。我们可以借助vectalign工具让几乎任意两个svg图形之间都能够进行morphing变换。

网址:https://github.com/bonnyfone/vectalign

工具:vectalign-0.2-jar-with-dependencies.jar.zip

SVG矢量动画的更多相关文章

  1. Android使用SVG矢量动画(二)

    上篇我们学习了怎么显示SVG矢量图像,当然还有一个更强大的功能,就是让SVG图像动起来,先上一张效果图吧: 要实现上述动画效果,就得用AnimatedVectorDrawable这个类了,它就是负责V ...

  2. Logo小变动,心境大不同,SVG矢量动画格式网站Logo图片制作与实践教程(Python3)

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_207 曾几何时,SVG(Scalable Vector Graphics)矢量动画图被坊间称之为一种被浏览器诅咒的技术,只因为糟糕 ...

  3. Android SVG矢量资源的使用方法

    VectorDrawable 与 SVG Android 5.0(Lollipop, API 21)后,新增了<vector>标签,以VectorDrawable的形式支持SVG类型矢量图 ...

  4. Android中矢量动画

    Android中矢量动画 Android中用<path> 标签来创建SVG,就好比控制着一支画笔,从一点到一点,动一条线. <path> 标签 支持一下属性 M = (Mx, ...

  5. Android使用SVG矢量创建很酷的动态效率!

    尊重原创,欢迎转载.转载请注明: FROM  GA_studio   http://blog.csdn.net/tianjian4592 一个真正酷炫的动效往往让人虎躯一震,话不多说.咱们先瞅瞅效果: ...

  6. svg矢量图

    svg简介 Scalable Vector Graphics 可缩放矢量图形 SVG 图像在放大或改变尺寸的情况下其图形质量不会有所损失 svg知识点 svg如何绘图 svg和cnavas区别 svg ...

  7. Android 使用 SVG 矢量图

    android svg矢量图 可能包含的操作有: SVG图还包括改变颜色,透明度,大小,矩阵操作(平移.旋转.缩放),selector, (图标,背景,按钮),动画,等 setTint(int Col ...

  8. SVG路径动画解密

    原文:SVG路径动画解密 原文链接:http://www.gbtags.com/gb/share/5581.htm SVG路径动画效果现在貌似越来越多网站都使用了,给我的感觉就像是一段时间的流行而已, ...

  9. 【Web动画】SVG 线条动画入门

    通常我们说的 Web 动画,包含了三大类. CSS3 动画 javascript 动画(canvas) html 动画(SVG) 个人认为 3 种动画各有优劣,实际应用中根据掌握情况作出取舍,本文讨论 ...

随机推荐

  1. SyntaxError Non-ASCII character '\xe5' in file

    环境: windows7 Python 2.7.16 在源码中添加注释之后报错如下: (WeChat) E:\WorkHome\Wechat>python firstBlood.py Trace ...

  2. Nginx负载均衡health_check分析

    在Nginx负载均衡中,我们很难保证说每一台应用服务器都能一直正常的运行下去.但是我们可以通过设置Nginx来检测这些应用服务器,检测这些服务器当中不能访问的. Nginx的检测方式分为两种,一种是被 ...

  3. nyoj252-01串

    01串 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描述 ACM的zyc在研究01串,他知道某一01串的长度,但他想知道不含有"11"子串的这种长度的0 ...

  4. redis实现集群加主从复制

    a)原理 (1)前提背景:如何解决redis横向扩展的问题----redis集群实现方式 (2)介绍redis 集群 ① Redis 集群是一个提供在多个Redis间节点间共享数据的程序集 ② 优势: ...

  5. 《你又怎么了我错了行了吧》【Alpha】Scrum meeting 1

    第一天 日期:2019/6/14 前言: 第1次会议在9C-405召开 4个人讨论了整体代码的框架.布局.找出需要改进的地方重点讨论.明确编码的具体分工,每个人搭建好环境. 1.1 今日完成任务情况以 ...

  6. github插件

    可能是迄今为止最好的GitHub代码浏览插件,基本实现浏览器变成代码阅读器,支持目录列表,交叉索引等功能: O网页链接 ​​​​ http://weibo.com/1963193953/Fdj2cFQ ...

  7. ajax短轮询+php与服务器交互制作简易即时聊天网站

    主流的Web端即时通讯方案大致有4种:传统Ajax短轮询.Comet技术.WebSocket技术.SSE(Server-sent Events). 本文主要介绍ajax短轮询的简易实现方式. 看懂此文 ...

  8. 洛谷—— P1262 间谍网络

    https://www.luogu.org/problem/show?pid=1262 题目描述 由于外国间谍的大量渗入,国家安全正处于高度的危机之中.如果A间谍手中掌握着关于B间谍的犯罪证据,则称A ...

  9. [using_microsoft_infopath_2010]Chapter8 使用InfoPath表单web部件

    本章概要: 1.配置web part 2.创建web part连接 3.创建表单参数 4.利用其它浏览器表单参数

  10. C++表达式求值(利用数据结构栈)

    唉,刚刚用C++又又一次写了一个较完好的表达式求值程序,最后精简后程序还不到100行.这不经让我 想到了大一上学期刚学c语言时自己费了好大的劲,写了几百行并且功能还不是非常齐全(当时还不能计算有括号的 ...