前言
引入 SVG 还需要从图片的数字化说起。一般来说,将图片存储为数据有两种方案。其一、就是我们传统使用的位图 (光栅图)。即将图片看成在平面上密集排布的点的集合。每个点发出的光有独立的频率和强度,反映在视觉上,就是颜色和亮度。位图拥有一个庞大的家族,包括常见的 JPEG/JPG, GIF, TIFF, PNG, BMP 等。第二种方案就是矢量图(SVG 就是其中的一种)。它用抽象的视角看待图形,记录其中展示的模式而不是各个点的原始数据。它将图片看成各个 "对象" 的组合,用曲线记录对象的轮廓,用某种颜色的模式描述对象内部的图案(如用梯度描述渐变色)。比如一张留影,被看成各个人物和背景中各种景物的组合。这种更高级的视角,正是人类看世界时在意识里的反映。矢量图格式有 CGM,
SVG, AI (Adobe Illustrator), CDR (CorelDRAW), PDF, SWF, VML 等等。
矢量图中简单的几何图形,只需要几个特征数值,就可以确定。比如三角形,只需要确定三个顶点的坐标。圆只需要确定圆心的坐标和半径。描述它的函数已知的曲线也只需要几个参数就能够确定。如正弦曲线、各种螺线等等。如果用位图记录这些几何图案,则需要包含组成线条的各个像素的数据。除了大大节省空间,矢量图还具有完美的伸缩性。因为记录的是图形的特征,图形的尺寸任意变化时,都只是做着相似变换,不会出现模糊和失真。相反,位图的图片放大到超出原有大小时,各个像素点之间出现空缺,即使用某种填充,也会出现模糊锯齿等现象,不如矢量图精确。因而矢量图很适合用于记录诸如符号、图标等简单的图形。而位图则适合于没有明显规律的、颜色丰富细腻的图片。
说起 SVG 可能有些人不怎么熟悉,但提及 xml,对于大部分人来说都是耳熟能详的。其实,SVG 也就是使用 xml 定义的图形。当然,主流的解析 xml 的工具一般都可以拿来解析 svg。SVG 是从 Android5.0 版本开始被引入到平台上的。下面我就 SVG 的话题,根据我这段时间的探索进程一一展开。
一、SVG 简介
根据网络上的定义:SVG 是可缩放矢量图形,是基于可扩展标记语言(标准通用标记语言的子集),用于描述二维矢量图形的一种图形格式。它由万维网联盟制定,是一个开放标准。
SVG 的优势
首先简要解释一下矢量图像格式和位图图像格式的区别。矢量图像用点和线来描述物体,所以文件会比较小,同时也能提供高清晰的画面,适合于直接打印或输出。而位图图像的存储单位是图像上每一点的像素值,因此一般的图像文件都很大,会占用大量的网络带宽。SVG 是一种矢量图形格式,GIF、JPEG 是光栅文件格式。有了两者的概念后,SVG 较 GIF、JPEG 的优势显而易见。
任意放缩
用户可以任意缩放图像显示,而不会破坏图像的清晰度、细节等。
文本独立
SVG 图像中的文字独立于图像,文字保留可编辑和可搜寻的状态。也不会再有字体的限制,用户系统即使没有安装某一字体,也会看到和他们制作时完全相同的画面。
较小文件
总体来讲,SVG 文件比那些 GIF 和 JPEG 格式的文件要小很多,因而下载也很快。
超强显示效果
SVG 图像在屏幕上总是边缘清晰,它的清晰度适合任何屏幕分辨率和打印分辨率。
超级颜色控制
SVG 图像提供一个 1 600 万种颜色的调色板,支持 ICC 颜色描述文件标准、RGB、线 X 填充、渐变和蒙版。
交互和智能化
SVG 面临的主要问题一个是如何和已经占有重要市场份额的矢量图形格式 Flash 竞争的问题,另一个问题就是 SVG 的本地运行环境下的厂家支持程度。
二、SVG 的解析
上文提到 Android5.0 时引入了 SVG 特性,其中必然会涉及到 SVG 图片的加载与解析。而 svg 本质上就是 xml 文件,所以从解析角度来看,能解析 xml 文件的工具应该几乎都可以用来解析 svg 文件。
1、DOM 解析
查看 Android 源码可以看出,5.0 引入 svg 后并没有使用 dom 进行解析 svg 源文件,虽然 svg 号称完全支持 dom 标准。笔者从 dom 解析的过程可以看出,Dom 解析是将 xml 文件全部载入,组装成一颗 dom 树,然后通过节点以及节点之间的关系来解析 xml 文件。虽然一般情况下,svg 文件是比较小的,但也不乏有些很复杂的图片会上升到 M 级别,如果在解析时需要全部载入,对于 Android 系统来说时比较耗时的,这也许就是 dom 遭 Android 淘汰的原因之一吧。
2、SAX 解析
SAX(Simple API for XML) 解析器是一种基于事件的解析器,它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作的。当事件源产生事件后,调用事件处理器相应的处理方法,一个事件就可以得到处理。在事件源调用事件处理器中特定方法的时候,还要传递给事件处理器相应事件的状态信息,这样事件处理器才能够根据提供的事件信息来决定自己的行为。SAX 解析器的优点是解析速度快,占用内存少。非常适合在 Android 移动设备中使用
3、PUll 解析
PULL 解析器的运行方式和 SAX 类似,都是基于事件的模式。不同的是,在 PULL 解析过程中,我们需要自己获取产生的事件然后做相应的操作,而不像 SAX 那样由处理器触发一种事件的方法,执行我们的代码。PULL 解析器小巧轻便,解析速度快,简单易用,非常适合在 Android 移动设备中使 用,Android 系统内部在解析各种 XML 时也是用 PULL 解析器
三、SVG 在 Android5.0 以上版本中的使用
- <?xml version="1.0" encoding="utf-8"?>
- <vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="180dp"
- android:height="320dp"
- android:viewportWidth="180"
- android:viewportHeight="400">
- <path
- android:name="sharp_rect"
- android:fillColor="#000000"
- android:pathData="M 320,180 L 0,320 0,0 180,0 z" />
- </vector>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
使用 ImageView 引用 vector 资源 sharp_rect
[activity_main.xml]
- "http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
- android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
- "@drawable/sharp_rect"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- />
- </RelativeLayout>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
Demo 附件:
效果图:
- <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:duration="500"
- android:interpolator="@android:interpolator/decelerate_cubic"
- android:propertyName="pathData"
- android:valueType="pathType"
- android:repeatMode="reverse"
- android:repeatCount="1"
- android:valueFrom="M100,100 L400,250 L100,400 L100,400 z"
- android:valueTo="M100,100 L400,100 L400,400 L100,400 z" />
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
[animated_play.xml]
- <?xml version="1.0" encoding="utf-8"?>
- <animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/play_icon">
- <target
- android:animation="@animator/to_stop"
- android:name="play" />
- </animated-vector>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
Demo 附件:
效果图:
3、小结
Android5.0 关于这块新特性的添加主要是依赖于 Vctor,对应的类为 VectorDrawable 以及 AnimatedVectorDrawable。前者主要用于矢量图的加载,后者主要用于矢量动画的加载。二者在使用过程中要区分对待。
四、Android5.0 以下使用 SVG 探索总结
经过这短时间的不断摸索与实验,按照 svg_android 组织的方法主要有以下两种:
1、基于 svg_android 库
抽取类似 svg_android 库中适合 5.0 以下的,且可以解析 svg 的文件,自定义类似 svg 的控件,进行 Android 工程的搭建(该实例使用 sax 解析 svg 文件)。
对应实例:【SVGMapView-master】
Demo 附件:
效果图:
【说明】 该方法需要开发者自己去重写解析函数,目前该实例并不能支持所有的 svg 语法的解析,如将该方法布置到项目中,需要大量拓展解析甚至加载 SVg 的功能函数。
2、基于 JNI 技术
加载及加息 svg 的工作交给 C/C++ 处理,上层使用 java 调用对应. so 库暴露的接口。
对应实例:【ImageViewSvg】
Demo 附件:
效果图:
【说明】该方案虽然使用了 JNI 技术来加载并解析 svg 文件,但目前其解析度有限,功能较为单一,如需要布置该方案于项目中,对于 jni 侧也需要扩展大量的 svg 解析函数。且需要优化对应的加载处理环节。
五、总结
从整体上看,目前是有可能将 svg 应用到 Android5.0 以下版本的。但其的稳定性,以及后续的工作量是需要我们仔细斟酌的问题之一。
来源: