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 矢量图是个什么东东

Snip20170626_1.png

看到没有,这就是一个 SVG 矢量图片,就是一个 xml 文件,右边是预览,先说下,这东西的好处:缩放不失真,体积小。这一个 SVG 图片只有970个字节...强大吧,比 png 格式的图片强的没边了吧,png 我们还得适配,做多套,然后一个一个改名字复制到工程里,有了 SVG 妈妈再也不担心我们写作业啦...

解析 SVG xml 文件的一些参数

这里需要解释下这里的几个标签:

  • android:width \ android:height:定义图片的宽高

  • android:viewportHeight \ android:viewportWidth:定义图像被划分的比例大小,例如例子中的500,即把200dp大小的图像划分成500份,后面Path标签中的坐标,就全部使用的是这里划分后的坐标系统。
    这样做有一个非常好的作用,就是将图像大小与图像分离,后面可以随意修改图像大小,而不需要修改PathData中的坐标。

  • android:fillColor:PathData中的这些属性就不详细讲了,与Canvas绘图的属性基本类似。

这里有一分详细的属性说明:

<vector>                   定义这个矢量图
    android:name           矢量图的名字
    android:width          矢量图的内部(intrinsic)宽度,支持所有Android系统支持的尺寸,通常使用dp
    android:height         矢量图的内部(intrinsic)高度
    android:viewportWidth  矢量图视图的宽度,视图就是矢量图path路径数据所绘制的虚拟画布
    android:viewportHeight 矢量图视图的高度
    android:tint           矢量图的tint颜色。默认是没有tint颜色的
    android:tintMode       矢量图tint颜色的Porter-Duff混合模式,默认值为src_in。(src_in,src_over,src_atop,add,screen,multiply) 
    android:autoMirrored   设置当系统为RTL(right-to-left)布局的时候,是否自动镜像该图片。比如阿拉伯语。
    android:alpha          该图片的透明度属性

<group>                    设置路径做动画的关键属性的
    android:name           定义group的名字
    android:rotation       定义该group的路径旋转多少度
    android:pivotX         定义缩放和旋转该group时候的X参考点。该值相对于vector的viewport值来指定的。
    android:pivotY         定义缩放和旋转该 group 时候的Y参考点。该值相对于vector的viewport值来指定的。
    android:scaleX         定义X轴的缩放倍数
    android:scaleY         定义Y轴的缩放倍数
    android:translateX     定义移动X轴的位移。相对于vector的viewport值来指定的。
    android:translateY     定义移动Y轴的位移。相对于vector的viewport值来指定的。

<path>
    android:name           定义该path的名字,这样在其他地方可以通过名字来引用这个路径
    android:pathData       和SVG中d元素一样的路径信息。
    android:fillColor      定义填充路径的颜色,如果没有定义则不填充路径
    android:strokeColor    定义如何绘制路径边框,如果没有定义则不显示边框
    android:strokeWidth    定义路径边框的粗细尺寸
    android:strokeAlpha    定义路径边框的透明度
    android:fillAlpha      定义填充路径颜色的透明度
    android:trimPathStart  从路径起始位置截断路径的比率,取值范围从0到1;注意从一半到起始动画为from-0.5-to-0
    android:trimPathEnd    从路径结束位置截断路径的比率,取值范围从0到1;注意从一半到结束动画为from-0.5-to-1.0
    android:trimPathOffset 设置路径截取的范围,取值范围从0到1
    android:strokeLineCap  设置路径线帽的形状,取值为 butt, round, square.
    android:strokeLineJoin 设置路径交界处的连接方式,取值为 miter,round,bevel.
    android:strokeMiterLimit 设置斜角的上限

<clip-path>                定义当前绘制的剪切路径。注意,clip-path 只对当前的 group 和子 group 有效
    android:name           定义clip-path的名字
    android:pathData       android:pathData的取值一样。

根元素<vector>上有两个宽高设置,其中viewport是指矢量图里面的画布大小,而android:width和android:height是指该矢量图所对应的VectorDrawable的大小。

关于tintMode:  
在5.0以后我们就可以为bitmap或者是9-patch定义一个透明的遮罩。BitmapDrawable和NinePatchDrawable使用setTint()方法。
而在xml文件中使用android:tint和android:tintMode这两个属性。

注意点:使用android:tint指定颜色时一定要带透明度。#50ff00ff也就是说是8位的色值而不是6位的。

属性说明: 
android:tint: 设置的是颜色 
android:tintMode:设置的是类型(src_in,src_over,src_atop,add,screen,multiply)

类型说明: 
src_in 只显示设置的遮罩颜色。 相当于遮罩在里面。 
src_over遮罩颜色和图片都显示。相当于遮罩在图片上方。(特别是色值带透明度的) 
src_atop遮罩在图片上方 
multiply 混合色遮罩 
screen 
add 混合遮罩,drawable颜色和透明度。

好了下面开始介绍 SVG 啦


概念

首先,需要讲解两个概念——SVG和Vector。

SVG,即Scalable Vector Graphics 矢量图,这种图像格式在前端中已经使用的非常广泛了

Vector,在Android中指的是Vector Drawable,也就是Android中的矢量图

因此,可以说Vector就是Android中的SVG实现,因为Android中的Vector并不是支持全部的SVG语法,也没有必要,因为完整的SVG语法是非常复杂的,但已经支持的SVG语法已经够用了,特别是Path语法,几乎是Android中Vector的标配

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 图片的使用

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 图片一样使用就好啦,你可以试一下。


5.0 以下系SVG图片的使用

SVG 在 4.x 版本上的兼容根据 SVG 使用范围的变化,配置也是逐步增加的

1. 在 imageview 中使用 SVG

这时 imageview 就不行了,我们需要使用 AppCompatActivity 或是 AppCompatImageView,这时我们需要导入 V7 包

 compile 'com.android.support:appcompat-v7:25.1.0'

gradle 需要如下配置:

//gradle2.0及以上:
android {
  defaultConfig {
  vectorDrawables.useSupportLibrary = true
}}

//gradle 1.5
android {
  defaultConfig {
    // Stops the Gradle plugin’s automatic rasterization of vectors
    generatedDensities = []
  }
  // Flag to tell aapt to keep the attribute ids around
  aaptOptions {
    additionalParameters "--no-version-vectors"
  }
}

系统会在 4.x 版本时对 SVG 自动生成相应的 drawable 图,此时 SVG 是没有无限拉伸特性的,gradle 的配置目的是去这个


官方解释

举个例子:

 <android.support.v7.widget.AppCompatImageView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_centerInParent="true"
      app:srcCompat="@drawable/ic_android_black_24dp"
    />

资源设置不能用 src 了,必须使用 srcCompat ,这时我们能看到图而不是去 SVG 的特性了

2. 在更广阔的范围中使用 SVG

这时上面的设置就不够了,我们在 view 所在的 activity 或是全局添加下面的设置

static {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }

然后这还不够,我们必须给 SVG 图片添加一个容器,比如 selector,这样我们才能正常使用,比如给 textview 设置图片,自定义属性设置图片

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/vc_halfstart_24dp"></item>
</selector>

这个 vc_halfstart_24dp 就是 SVG 图片

3. 在代码中使用相关 API

这个我们必须要添加官方的 vectorDrawable 支持库了,最低支持到 23.2.0

implementation 'com.android.support:support-vector-drawable:28.0.0'

这样基本就没啥问题了


svg 解析

SVG 配合自定义 view 的话,就得我们读取 SVG 然后转换成 path 路径来画了,SVG 实质上也是 xml 文件,所以解析 xml 文件的思路也使用,当然还有其他一些 SVG 转 path 的思路

SVG前戏—让你的View多姿多彩 一文中提供了一些思路,大家不妨去看看


参考资料:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容