① android图片系列 (2) - 静态 SVG 图片
SVG 图片是一种可支持任意缩放的图片格式,使用 xml 定义,使用 canvas 中 path 路径来完成绘制,和我们传统使用的 BitMap位图有很大的区别。
SVG 在前端早就普及了,在android 中是 google 是在5.0之后开始支持的,14年出来之后兼容是个大问题,随着2016.2 V7包 23.2.0版本的发布才算是有个相对完善的兼容使用方案。
SVG 的概念我就不写了,拿来主义啦,原文: Android Vector曲折的兼容之路
不瞎逼逼,我们先来看一看 android 中的 SVG 矢量图是个什么东东
看到没有,这就是一个 SVG 矢量图片,就是一个 xml 文件,右边是预览,先说下,这东西的好处:缩放不失真,体积小。这一个 SVG 图片只有970个字节...强大吧,比 png 格式的图片强的没边了吧,png 我们还得适配,做多套,然后一个一个改名字复制到工程里,有了 SVG 妈妈再也不担心我们写作业啦...
这里需要解释下这里的几个标签:
这里有一分详细的属性说明:
好了下面开始介绍 SVG 啦
首先,需要讲解两个概念——SVG和Vector。
SVG,即Scalable Vector Graphics 矢量图,这种图像格式在前端中已经使用的非常广泛了
Vector,在Android中指的是Vector Drawable,也就是Android中的矢量图
因此,可以说Vector就是Android中的SVG实现,因为Android中的Vector并不是支持全部的SVG语法,也没有必要,因为完整的SVG语法是非常复杂的,但已经支持的SVG语法已经够用了,特别是Path语法,几乎是Android中Vector的标配
Android以一种简化的方式对SVG进行了兼容,这种方式就是通过使用它的Path标签,通过Path标签,几乎可以实现SVG中的其它所有标签,虽然可能会复杂一点,但这些东西都是可以通过工具来完成的,所以,不用担心写起来会很复杂。
Path指令解析如下所示:
支持的指令:
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,FLAG1,FLAG2,X,Y):弧线
Z = closepath():关闭路径
坐标轴为以(0,0)为中心,X轴水平向右,Y轴水平向下
所有指令大小写均可。大写绝对定位,参照全局坐标系;小写相对定位,参照父容器坐标系
指令和数据间的空格可以省略
同一指令出现多次可以只用一个
注意,’M’处理时,只是移动了画笔, 没有画任何东西。 它也可以在后面给出上同时绘制不连续线。
关于这些语法,开发者需要的并不是全部精通,而是能够看懂即可,其它的都可以交给工具来实现。
这里有一篇 Android vector标签 PathData 画图超详解 详细描述了 SVG 中 path 的绘制
好了概念性的东西说完了,我们来看看
SVG 的使用分2种,一种是静态 SVG 矢量图,就是本文的主角,本章节主要谈论的东西,另一种是 SVG 矢量动画,是SVG 的高级应用,是给静态 SVG 加上objectAnimator 动画,应用的很广泛,是实现 android icon 动态交互的核心做法。
上面的SVG 图大家都看到了,我们就是写一个 xml 的文件,里面承载的标签都是描述如何绘制我们想要的图案的,画布大小,颜色,路径等,然后交给系统去绘制。
现在让我们来看看 SVG 在 andorid 中如何应用,如何兼容5.0以下版本。
SVG 虽然早早就在前端使用了,但是 android 上开始支持 SVG 的使用还是从5.0开始的,在5.0以上系统的使用很简单,和之前一样使用 PNG 图片一样
首先 android 中的 SVG 图片的承载方式是一个 xml 文件,所以UI 给我们的 SVG 图片是不能直接使用的,这里 google 给我们提供加载方式
Android studio 在 2.3.3 的版本中可以直接使用 svg,新建一个 SVGDemo项目,新建 Vector Asset 文件:app-> main -> New -> Vector Asset 如图所示:
我们选择 Local File 就是选择本地svg文件进行导入,对文件命名后点击 Next ->Finish 在 drawable目录 下就添加了一个.xml的文件
好了这样一个 svg 图片我们算是加入到我们的工程里里了,可以直接使用了。当然在此之前我们把 SVG 图片放在那个 drawable 文件夹呢。对于这个问题就要说一下了:
有一点需要解释一下,svg 矢量图文件我们放在drawable 根目录即可。android 系统不会根据你把 svg 矢量图存放在不同的 drawable 文件夹,对图片进行分辨率上的缩放,因此我们不用像使用 PNG 图片时准备多套图片了。我们导入 SVG 图片默认存放的地址就是 drawable根目录,所以我们就放这里就好了,当然也可以自己写SVG 图片,都是 xml 的,自己写完 path 路径后都是可以查看预览的,一般也不会自己写,都是UI 的活。
这样就 ok啦,5.0以上的系统SVG你就像一般 png 图片一样使用就好啦,你可以试一下。
SVG 在 4.x 版本上的兼容根据 SVG 使用范围的变化,配置也是逐步增加的
这时 imageview 就不行了,我们需要使用 AppCompatActivity 或是 AppCompatImageView,这时我们需要导入 V7 包
gradle 需要如下配置:
系统会在 4.x 版本时对 SVG 自动生成相应的 drawable 图,此时 SVG 是没有无限拉伸特性的,gradle 的配置目的是去这个
举个例子:
资源设置不能用 src 了,必须使用 srcCompat ,这时我们能看到图而不是去 SVG 的特性了
这时上面的设置就不够了,我们在 view 所在的 activity 或是全局添加下面的设置
然后这还不够,我们必须给 SVG 图片添加一个容器,比如 selector,这样我们才能正常使用,比如给 textview 设置图片,自定义属性设置图片
这个 vc_halfstart_24dp 就是 SVG 图片
这个我们必须要添加官方的 vectorDrawable 支持库了,最低支持到 23.2.0
这样基本就没啥问题了
SVG 配合自定义 view 的话,就得我们读取 SVG 然后转换成 path 路径来画了,SVG 实质上也是 xml 文件,所以解析 xml 文件的思路也使用,当然还有其他一些 SVG 转 path 的思路
SVG前戏—让你的View多姿多彩 一文中提供了一些思路,大家不妨去看看
② 如何玩转Android矢量图VectorDrawable
创建Vector Drawable
从相似角度来看,VectorDrawable与标准SVG图形都是利用path值绘制完成的。不过如何利用SVG path绘制图形并不在本篇文章的探讨范围之内,大家可以点击此处从W3C网站处获取必要的说明资料。在本文当中,我们只需要了解到path标签的作用是进行图形绘制即可。让我们首先从SVG文件入手,看看以下图形是如何被绘制出来的:
这一图形共由五个主要部分所组成:
一个圆角四边形作为CPU主体,该四边形由两条拱状弧线构成。
四组各自包含五根线条的图形,用于充当CPU的外延线路。
虽然看起来有点繁杂,但大家其实用不着纠结于以上代码的具体含义,而且这完全不会影响到我们接下来要进行的VectorDrawable绘制工作。不过需要强调的是,我将前面提到的五大图形组成部分在代码中作为独立的区块来处理,这是为了增强代码内容的可读性。
③ 安卓开发中矢量图的绘制及动画
矢量图也称为面向对象的图像或绘图图像,是根据几何特性来绘制的图形,在安卓开发中可以使用失量图代替原来的图片资源,矢量图具有占用空间小和可以随意缩放但不失真的优势,在我的多个项目中都有运用。
通过学习和实践,我总结了一些与矢量图相关的知识,方便今后更好的使用矢量图,同时也可以供大家查阅参考。
绘制矢量图之前需要先定义画布的宽高,后续的绘制效果都展示在这个画布上。在绘制过程中需要输入的坐标就是这个画布上的点。
安卓的矢量图常见于 drawable 文件夹下,是一个xml文件,由 vector 标签包裹,在 vector 标签中可包含多个 path 标签,依次叠加显示。
在矢量图中最重要的就是 path 属性,图像的样式就是由 path 属性中的数据绘制而成,这些数据由不同的命令组合而成,下面就介绍一些矢量图的绘制命令。
将前面的命令示例连接起来就可以生成一个完整的图像,它大概长这个样子:
画布的尺寸为500x500,图上的顶点是200,10的位置,也是我们开始作图的起点。通过这个图片可以更好的理解每一个绘图命令。
安卓中可以为矢量图添加动画效果,这样用户就可以看到一个动的图片,可以一定程度的提高app的交互效果。矢量图动画是图形内部的变化,可以做到View动画无法实现的效果。
这种动画针对的是矢量图中 path 字段的值,通过连续改变 path 字段的值而达到产生动画的效果。
注:pathData动画所需的AnimatedVectorDrawable最低要求API等级为25
实现一个矢量图动画需要以下几步:
1. 准备起始状态和结束状态的矢量图两张。
2. 创建动画配置文件。
3. 创建动画矢量图文件。
4. 启动动画。
基于这种要求,我准备了两个矢量图:
控制动画运行的是一个 objectAnimator ,此处把 objectAnimator 包裹在一个 set 中也是可以的,说白了就是执行这个动画文件。
ration 用来指定动画的持续时间。
propertyName 中的pathData指的就是矢量图中的pathData。
valueFrom 和 valueTo 一个是起始路径,一个是结束路径,可以想到,这个动画就是在持续修改pathData,从而达到展示动画的效果。而 valueFrom 和 valueTo 的值是直接从先前准备的矢量图中复制过来的,所以那个结束状态的矢量图中唯一有用的东西就是pathData属性,没有那个文件也无所谓。
valueType 这里必须填判型写pathType,这是专门用来计算path的类型。
此时,文件的最外层由 animated-vector 包裹,同时需要添加一个 drawable 参数,这个 drawable 用于指定动画应用于那个矢量图上,我们是要从未启用状态变成启用状态,所以是在未启用状态开始执行动画,在动画未开始的时候展示的也是未启用状态。此处我们指定为 @drawable/icon_filter_off 。
内部有一个 target 标签,这个标签可以有多个,分别对应不同的动画,但同一个 path 只能应用一个动画。
name 用于指定要执行动画的 path 。status正是我们为右下角小图标path设置的名称。
animation 用于指定需要执行的动画。此处引用我们刚刚创建的猛冲山动画资源 @animator/filter_turn_on 。
当我们创建枝中好动画矢量图之后,页面中引用的资源就不再是之前的静态矢量图了,需要把 ImageView 的图片替换成 @drawable/animated_filter_on
经过这么多的步骤,我们终于做出了一个矢量图动画,而且是一个。说实话,有点累,然而我这个状态切换的动画一套就要两个,所以我又加了一个回来的动画和对应的动画矢量图,一共六个文件,完成了筛选状态的两个切换动画。这还是比较简单的实现方式,对于两种状态切换的动画,网上还有一种使用selector的方式,这种方式更麻烦,而且使用方法并没有简单一些,所以我的选择是在需要切换状态的时候更改 ImageView 的图片资源,然后再执行动画。
trimPath动画相当于是改变了矢量图绘制的位置,是从头开始画还是从80%的位置开始画,然后再动态的修改这个百分比,从而达到动画的效果。理解起来倒不是很难。
先放一个我使用trimPath动画做的loading效果,这个动画效果被我用在LoadingDialog中,在界面加载的时候会重复播放这个动画。
android:name="load" 不用多说,这个是我们做动画时路径名称。这里为了让心电图路径更清晰,我设置了描边宽度为20( android:strokeWidth="20" ),同时还要设置描边的颜色才能展示出来。后面的 android:trimPathStart="0" 和 android:trimPathEnd="0" 是本次trimPath动画的重点。
这两个属性都设置为0是因为动画的起始帧都为0,然后通过 objectAnimator 慢慢把这两个属性变为1,这样一个慢慢增长的动画就形成了。
网络上一个横线变成搜索按钮的示例是将这两个属性分别应用到了两个 path 上,而我是将两个属性同时应用到一个 path 上,原理都是一样的。
在配置文件中,我将两个动画都设置为3秒且循环播放,起始点的动画慢于终点的动画1秒,达到只画中间1秒间隔线段的效果。和路径变形动画的区别是 android:valueType="floatType" ,我们只需要计算从0到1的数字,然后应用到 trimPathStart 和 trimPathEnd 字段上。至此,loading的动画就配置完了。
这一步已经没什么可说的了,就是将指定的矢量图中指定的路径设置一个指定的动画。
通过几天的学习,已经大致掌握了矢量图的展示及动画的制作,但这一套流程下来成本比较高,是程序员方式的动画制作流程。除了制作成本,创意成本也是相当高的,一个好的创意能极大的提升用户体验,而好多时候我们的创意能够被实现也是很困难的。希望以后能实现一些更好的效果,让用户使用起来更舒服。
SVG—最简单的SVG动画
SVG路径(path)中的圆弧(A)指令的语法说明及计算逻辑
Android中的矢量图
Android高级动画(2)