Android动画之VectorDrawable矢量图实战
1. 矢量图SVG简介
Android 5.0系统中引入了 VectorDrawable 来支持矢量图(SVG),同时还引入了 AnimatedVectorDrawable 来支持矢量图动画。
所谓SVG(Scalable Vector Graphics),直译为可伸缩矢量图,具体内容可以参考矢量图百科。和一般的栅格图(比如PNG)相比,虽然其绘制速度较慢,却有以下的优点:
- 保存最少的信息,文件大小比位图要小,并且文件大小与物体的大小无关;
- 任意放大矢量图形,不会丢失细节或影响清晰度,因为矢量图形是与分辨率无关的。
从以上两个优点来看,在项目中使用矢量图至少可以缩小我们apk包的尺寸,而且可以在屏幕适配时提供很大的方便,因为矢量图是分辨率无关的。
2. Android中的Vector
SVG是一套标准,VectorDrawable是Android中的实现,但是VectorDrawable 并没有支持所有的 SVG 规范,目前只支持 PathData 和有限的 Group 功能。 所以对于使用 VectorDrawable 而言,我们只需要了解 SVG 的 PathData 规范即可。通过查看 PathData 文档,可以看到 path 数据包含了一些绘图命令,比如 :
- M: move to 移动绘制点;
- L:line to 直线;
- Z:close 闭合;
- C:cubic bezier 三次贝塞尔曲线;
- Q:quatratic bezier 二次贝塞尔曲线;
- A:ellipse 圆弧;
每个命令都有大小写形式,大写代表后面的参数是绝对坐标,小写表示相对坐标。参数之间用空格或逗号隔开
命令详解:
- M (x y) 移动到x,y;
- L (x y) 直线连到x,y,还有简化命令H(x) 水平连接、V(y)垂直连接;
- Z,没有参数,连接起点和终点;
- C(x1 y1 x2 y2 x y),控制点x1,y1 x2,y2,终点x,y;
- Q(x1 y1 x y),控制点x1,y1,终点x,y;
- A(rx ry x-axis-rotation large-arc-flag sweep-flag x y) :
- rx ry 椭圆半径
- x-axis-rotation x轴旋转角度
- large-arc-flag 为0时表示取小弧度,1时取大弧度
- sweep-flag 0取逆时针方向,1取顺时针方向
以下是绘制三角形的VectorDrawable实例:
<?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="64dp" android:width="64dp" android:viewportHeight="100" android:viewportWidth="100"> <path android:fillColor="#000000" android:pathData="M25,0 l 50,50 -50,50Z"/> </vector>
首先vector 标签是一个drawable对象,所以是放在res/drawable目录的。
vector 标签下有android:width和android:height属性,这两个属性是必填的,定义矢量图形的绝对大小,虽然说是矢量图形随意缩放,但是不能说这里不定义宽高直接到要设置到的目标控件上定义控件的宽高,这样是不允许的,一定要设置这个绝对宽高,要不然会报错。
然后还有个android:viewportHeight和android:viewportWidth属性,这个是画布宽高,也是必填的,定义Path路径的时候就必须在这个画布大小里去绘制,超出画布就显示不出来了。
path标签android:fillColor属性定义绘制颜色,android:pathData定义绘制路径。
M25,0 l 50,50 -50,50Z这个路径表示:
- 在100*100的画布内,先把绘制点移动到绝对坐标(25,0)这个点,然后画直线到(50,50)这个点,l指令是相对坐标,大写的L表示绝对坐标,那么l 50,50就是在原点(25,0)的x轴往前移50,往下移50,绝对坐标就是(75,50),也就是三角形的右边那个点;
- 然后从(50,50)这个点绘制到三角形最下面那个点(-50,50),这也是相对右边那个点相对坐标,也就是把(75,50)这个绝对坐标当作是原点(0,0),参作这个原点往后移动50再往下移动50,在整个画布中的绝对坐标就是(25,100)。
效果如下:
如果要绘制标准的SVG,可以是使用在线SVG Editor
另外,如果需要将SVG转化为VectorDrawable,还可以是使用在线工具Android SVG to VectorDrawable
更为重要的是,Android Studio自带Vector Assert工具,可以帮助我们生成矢量图;
- Material icon:使用官方自带的各种矢量图,内容很丰富;
- Local SVG file:使用第三方的SVG文件,比如从第三方图标网站:iconfont.cn中下载的图片都支持SVG;
3. Vector的配置和兼容性
正如上文所说,Android L开始提供了新的API VectorDrawable
可以使用SVG类型的资源,最初只能在21以上版本中使用。
为了让低版本也可以支持矢量图,Gradle Plugin 1.5加入了如下功能:
- buildVersion>=21时,Vector矢量图功能不变;
- buildVersion<21时,编译时,自动转换把Vector矢量图转化为PNG;
再后来Google升级了support library,官方向后兼容了矢量图的使用。矢量图兼容到API7,矢量图动画兼容到API11。
3.1 appcompat-v:23.2.0
因此要在低版本上兼容矢量图,就需要在项目中引入新的兼容库support-vector-drawable,并且appcompat-v7库的版本要在23.2.0+。
compile 'com.android.support:appcompat-v7:23.2.0'
3.2 gradle
而且你还要修改下gradle的相关配置,不要让gradle在构建的时候为你在低版本(API21以下)的情况下生成针对于不同密度的png文件,因为android studio1.4的时候支持了矢量图。
如果你的gradle插件的版本为2.0以下,你应该这么修改:
android { defaultConfig { // 不让gradle自动生成不同屏幕分辨率的png图 generatedDensities = [] } aaptOptions { additionalParameters "--no-version-vectors" } }
现在大部分人的gradle插件版本是2.0+,只要这样修改就好:
android { defaultConfig { vectorDrawables.useSupportLibrary = true } }
经过上面这几步的修改,就可以在项目中使用矢量图了。下面我们就正式来说说怎么使用。
4. Vector和属性动画结合使用
先看下效果图,这是一个代表文件下载的图片,是通过矢量图绘制的。我们通过将其和属性动画结合,实现了下载过程中的动画效果:箭头跳跃+横线反复出现
4.1 Vector矢量图
首先我们看一下图标的矢量图:
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24.0" android:viewportHeight="24.0"> <group android:name="arrow_location"> <path android:name="arrow_pic" android:fillColor="#FF000000" android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7z"/> </group> <path android:name="bar" android:fillColor="#FF000000" android:pathData="M5,18v2h14v-2H5z"/> </vector>
矢量图中有两个Path标签,第一个来绘制箭头,第二个来绘制底下的横线。细心的读者已经发现,第一个Path标签外被Group标签包裹,这是因为path标签中没有坐标变化的属性,这些属性在group标签中,要使用这些标签就必须在group中绘制。
4.2 ObejctAnimator
在Android属性动画Animator实现卫星Button中已经介绍了关于如何动态使用属性动画。本文的属性动画将以静态XML文件的出现,但是其内容是一样的。
如有要实现箭头跳跃的动画,就要让箭头的"translateY"属性向上移动,然后反复执行。为了让移动更有跳跃的感觉,interpolator被设为overshoot。
“arrow_jump.xml”文件如下:
<set xmlns:androd="http://schemas.android.com/apk/res/android"> <objectAnimator androd:duration="500" androd:interpolator="@android:interpolator/overshoot" androd:propertyName="translateY" androd:repeatCount="infinite" androd:repeatMode="reverse" androd:valueFrom="0" androd:valueTo="-3" androd:valueType="floatType" > </objectAnimator> </set>
"bar_drawing.xml"实现动画下方横线反复出现的过程。
<set xmlns:androd="http://schemas.android.com/apk/res/android"> <objectAnimator androd:duration="500" androd:propertyName="trimPathEnd" androd:repeatCount="infinite" androd:repeatMode="reverse" androd:valueFrom="0" androd:valueTo="1" androd:valueType="floatType"> </objectAnimator> </set>
这里要特别说明下属性* trimPathEnd,另外还有个属性 trimStartEnd*,其中trim是截取的意思,PathStart代表开始时的图像,PathEnd代表结束时的图像,变化的初始值和终值代表绘制的比率,从0变化到1,也就代表的是从完全没有到完全绘制出来,即从无到有。
持外两个属性属性动画最外层都是set标签,用户可以根据自己设计加入更多的属性动画标签ObjectAnimator。
4.3 animated-vector 粘合剂
如何将矢量图和属性动画结合起来呢,这就需要们的粘合剂*animated-vector *文件,在其中建立矢量图和动画的对应关系,如下:
“file_download.xml"
<?xml version="1.0" encoding="utf-8"?> <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/ic_file_download_black_24dp"> <target android:animation="@animator/arrow_jump" android:name="arrow_location"/> <target android:animation="@animator/bar_drawing" android:name="bar"/> </animated-vector>
其中animated-vector的android:drawable属性代表要控制的对象是哪一张矢量图。targe标签代表的动画和对象的一个对应关系,animation代表要加载的动画文件,name代表矢量图文件中的哪一个部分。这里两个target分别给。
更需要注意的是,位置移动所操控的属性并不是矢量图中path标签的,而是group标签的内容,所以箭头的name标准建立在group之中,arrow_jump动画绑定的对象也是group。同时,* trimPathEnd属性是Path的属性,所以动画绑定对象应该是Path*。
4.4 布局和模拟
Activity中的布局如下:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <LinearLayout android:orientation="vertical" android:gravity="center" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/image" android:layout_marginTop="5dp" android:onClick="anim" android:layout_width="100dp" android:layout_height="100dp" app:srcCompat="@drawable/file_download"/> </LinearLayout> </ScrollView>
需要注意的是,ImageView的app:srcCompat被设为粘合剂文件” file_download“。另外因为使用了app:srcCompat这个自定义的属性,需要加入命名空间xmlns:app="http://schemas.android.com/apk/res-auto"
Activity中对应的源码也很简单,点击图片模拟下载过程并开始动画,5秒之后下载结束,停止动画。
import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.widget.Toast; import static java.lang.Thread.sleep; public class MainActivity extends AppCompatActivity { ImageView mImageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mImageView = (ImageView) findViewById(R.id.image); } public void anim(View view) {//图片点击事件 ImageView imageView = (ImageView) view; Drawable drawable = imageView.getDrawable();//获得图片的Drawable属性 if(drawable instanceof Animatable) {//如果是属性动画 ((Animatable) drawable).start(); //开始动画 Toast.makeText(view.getContext(), "下载开始!",Toast.LENGTH_SHORT).show(); } new Thread(new Runnable() {//开启计时线程 @Override public void run() { try { sleep(5000); //睡眠5s,代表下载过程 runOnUiThread(new Runnable() {//在UI线程中停止动画 @Override public void run() { ((Animatable) mImageView.getDrawable()).stop(); Toast.makeText(getApplicationContext(),"下载完毕",Toast.LENGTH_SHORT).show(); } }); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } }
5. VectorDrawable的一些兼容问题:
如果使用appcompat-v:23.2.0+,兼容的API版本有比Android 5小的情况,还要注意有一些兼容新的问题:
- 在5.0以下的版本中,还无法使用Path Morphing(路径变化)属性;
- 在5.0以下的版本中,只能使用系统插值器;
- 在5.0以上版本中,需要把Drawable对象转化成AnimatedVectorDrawable之后才能使用
public void animL(View view) { ImageView imageView = (ImageView) view; AnimatedVectorDrawable drawable = (AnimatedVectorDrawable) getDrawable(R.drawable.fivestar_anim); imageView.setImageDrawable(drawable); if (drawable != null) { drawable.start(); } }
当然,如果最小版本都是5以上的,就没有这些问题了。
6. VectorDrawable的使用场景
最后借用前辈"徐医生"总结的VectorDrawable和Bitmap对比,为介大家绍适合VectorDrawable使用的场景:
7. 参考文献与阅读扩展

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
iOS 开发中使用 Core Data 应避免的十个错误
Core Data是苹果针对Mac和iOS平台开发的一个框架主要用来储存数据。对很多开发者来说Core Data比较容易入手但很难精通如果没有正确的学习方法你将很难真正理解它更不用说精通了。很多开发者常常在这方面犯一些错误而这篇文章列出了 开发者在iOS开发过程中使用Core Data常见的一些错误并对如何避免这些错误进行了分析。 1.不了解关键术语 对于iOS开发者来说会使用Core Data是一项必备技能。 没有它很多app都不会存在。当在互联网上四处搜索Core Data学习教程你很容易被各种各样的术语吓倒。事实上大部分学习教程都首先假定你已经知道了这些术语而如果你不了解这些术语那将会陷入困惑中。所 以首先要知道关键的术语。这里有一个备忘单可以用在学习Core Data的过程中这份备忘单展示了关键的词组 在以后的学习过程中你会遇到更多的术语但这些是初学者需要了解的最基本的部分。 2.完全忽视Core Data 当一项技术以难学“闻名”时你可能会忽略它特别是当你时间不够急着把app做出来的时候。 Core Data储存app数据的一个常见替代选择是使用XML属性列表虽然属性列表可以...
- 下一篇
Windows Phone 支持 Android 应用程序?来看看第三方开发者怎么说
近日,关于“Windows Phone支持Android应用程序”的话题变得很是热门,认同这一说法的就包括The Verge的编辑Tom Warren。其实在2014年2月份的时候,The Verge就已经有了这个说法的相关报道,当时The Verge称微软内部正在激烈争论是否让Windows Phone支持Android应用程序,以弥补Windows Phone应用匮乏的问题。 再看看最近,Tom Warren在Twitter上断言称: 在1月21日举行的发布会上,我坚信微软会公布一件事:提供对Android应用程序的支持。 在外界看来,微软让Windows Phone提供对Android应用程序的支持,这几乎是不可能的事,因此Tom Warren也遭到了一些同行的反驳。WMPU的编辑Lucason就认为这种说法不科学,他表示:“Windows Phone提供对Android应用程序的支持,等同于是直接抹杀了Windows Phone平台。原因其实很简单,如果真是这样,开发者将不会再为Windows Phone开发应用程序”。 然而Tom Warren和Lucason都只是微软生态的...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- MySQL8.0.19开启GTID主从同步CentOS8
- Mario游戏-低调大师作品