首页 > 代码库 > 关于Android中使用SVG特性的探索与总结

关于Android中使用SVG特性的探索与总结

前言

引入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版本开始被引入到Android平台上的。下面我就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以上版本中的使用

1、使用方法 
鉴于SVG有那么多的优点,Android于5.0版本将该特性引入。在5.0以上版本中使用方法如下: 
1)获取SVG图片数据 
第一种方法当然是从网上down了(一般直接用来测试使用),这里只给出几个常用素材下载网站: 
http://sc.chinaz.com/ 
http://www.freevectors.net 
http://www.freevectordownload.com/ 
其次就是手工制作了:真正做项目时,方法1肯定满足不了相应的需要了。这时我们只能自己动手来作图了(应该是美工来负责^_^||),相应最常用的软件就是PS、AI或者CDR也可以。具体制作方法这里就不做介绍了,直接上网搜就行。这里给出一个较为详细的例子:http://blog.csdn.net/tianjian4592/article/details/44733123 
2)将普通SVG图片数据转换成Android可用数据 
一般的SVG图片数据是直接在html或jsp中可以使用,Android中若想使用svg则需要中间环节先转换成Vector标签包括的xml文件(如果做动画的话,外面还需要包括一层animated-vector来引用vector资源),其中最重要的就是path元素,该元素就是图片加载显示过程中的绘制轨迹。具体转换方法网上查询得出有两种:一是手动改写,二是直接使用自动转化工具转换(http://inloop.github.io/svg2android/)。具体转换规则以及相应符号意义可以参见:http://www.w3.org/TR/SVG11/paths.html#PathData. 
3)在工程中使用 
svg在5.0以上的Android工程中使用相对较为简单,直接用drawable控件(如mageView等)引用第二步中转换得来的xml文件资源即可。 
2、Demo实例 
实例一:mytest(使用Drawable控件引用5.0新特性vector资源) 
【关键代码摘要】 
使用vector标签包括path元素 
[ sharp_rect.xml ]

<?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 ]

<RelativeLayout xmlns:android="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">

    <ImageView
        android:src=http://www.mamicode.com/"@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附件: mytest.zip 
效果图: 
技术分享

实例二:【VectorCard】使用5.0新特性animated-vector标签引用xml中的svg path元素 
【关键代码摘要】 
[ to_stop.xml ] 

<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附件: app.zip 
效果图: 
技术分享技术分享技术分享

3、小结 
Android5.0关于这块新特性的添加主要是依赖于Vctor,对应的类为VectorDrawable以及AnimatedVectorDrawable。前者主要用于矢量图的加载,后者主要用于矢量动画的加载。二者在使用过程中要区分对待。

四、Android5.0以下使用SVG探索总结

经过这短时间的不断摸索与实验,按照svg_android组织的方法主要有以下两种: 
1、基于svg_android库 
抽取类似svg_android库中适合5.0以下的,且可以解析svg的Java文件,自定义类似svg的控件,进行Android工程的搭建(该实例使用sax解析svg文件)。 
对应实例:【SVGMapView-master】 
Demo附件: SVGMapView-master.zip 
效果图: 
技术分享

【说明】 该方法需要开发者自己去重写解析函数,目前该实例并不能支持所有的svg语法的解析,如将该方法布置到项目中,需要大量拓展解析甚至加载SVg的功能函数。 
2、基于JNI技术 
加载及加息svg的工作交给C/C++处理,上层使用java调用对应.so库暴露的接口。 
对应实例:【ImageViewSvg】 
Demo附件: ImageViewSvg.zip 
效果图: 
技术分享

【说明】该方案虽然使用了JNI技术来加载并解析svg文件,但目前其解析度有限,功能较为单一,如需要布置该方案于项目中,对于jni侧也需要扩展大量的svg解析函数。且需要优化对应的加载处理环节。

五、总结

从整体上看,目前是有可能将svg应用到Android5.0以下版本的。但其的稳定性,以及后续的工作量是需要我们仔细斟酌的问题之一。

关于Android中使用SVG特性的探索与总结