SVG在Android中的使用

SVG是什么,使用它的优势

SVG是指可伸缩矢量图形 (Scalable Vector Graphics),它不同于传统的位图,不是通过存储图像中每一点的像素值来保存与使用图形,而是通过 XML 文件来定义一个图形。SVG 的方式是事先定义好怎么去画这个图,然后等要用的时候再把它去画出来。
SVG的优劣如下:

  • SVG 是在要用图的时候再把图画出来,所以理所当然的在图片显示的时候会花费更多的时间消耗更多的资源。
  • 同样由于上一个原因, SVG 并不太适合层次过于复杂细节过于繁多的图片。
  • 位图是事先已经画好的图片,所以适应性必然没有 SVG 好,同一张图片在不同分辨率下显示会有差异。
  • SVG 的文件里存储了绘制图片的相关信息,所以我们能够对图片的线条有一个非常清晰的感知,这在做动画的时候特别有用。
  • SVG 没有存储任何图像的像素信息,所以 SVG 的文件体积远小于传统的位图文件。
  • SVG 的文件画出来的图像是矢量图,所以不会存在失真的问题,理论上支持任何级别的缩放。

但是,要注意Android对于 SVG 的支持是从 Android L 开始的,它的 SDK 里面加入了 VectorDrawable , AnimatedVectorDrawable 等类帮助我们构建 SVG 图形以及动画,并且你可以在 xml 文件里面直接使用 <vector/> 标签绘制 SVG 图像以及 <animated-vector/> 标签为 SVG 图像分配动画。

SVG的配置

android{
  ...
  defaultConfig {
    ...
    vectorDrawables.useSupportLibrary = true
   }
  ...
}
dependencies {
  ...
  compile "com.android.support:appcompat-v7:21+" // 至少Api21
  ...
}

项目的Activity中都包含(通用做法是在BaseActivity中加)

static {
  AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
AppCompatImageView
<android.support.v7.widget.AppCompatImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:srcCompat="@drawable/svg_ic_arrow_right"/>
SVG参数相关

先看一个简单的SVG代码

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="132dp"
        android:height="132dp"
        android:viewportHeight="132.0"
        android:viewportWidth="132.0">
    <path
        android:pathData="M50,2 L80.813,2 L80.813,130 L50,130 L50,2 Z"
        android:strokeColor="#e33e2b"
        android:strokeWidth="8" />
</vector>

效果如下:

vector属性介绍
属性 描述
android:name 定义VectorDrawable的名字
android:width/android:height 定义图片的宽、高,支持所有尺寸单位,通常用dp指定
android:viewportWidth/android:viewportHeight 定义图片被划分的比例大小,例如上面的600.0,即把64dp平均分成500份,后面Path标签中的坐标,就全部使用的是这里划分后的坐标系统,width和height这两个值必须一样,否则图片会出现变形。
android:tint 定义图片的颜色,默认不设置颜色,该值会覆盖path标签中的android:fillColor值
android:tintMode 定义图片颜色为Porter-Duff blending 模式,默认值为 src_in
android:autoMirrored 当布局方向从右到左时,该图片是否自动被镜像
android:alpha 图片的透明度,取值范围(0-255),255表示全透明
group属性介绍

包含一组path或子group,通过group可以把多个path组合到一块形成一个图片

属性 描述
android:name 定义group的名字
android:rotation 定义group顺时针旋转的角度
android:pivotX、android:pivotY (pivotX,pivotY)定义了group缩放、旋转时的中心点
android:scaleX、android:scaleY X轴、Y轴的缩放倍数
android:translateX、android:translateY X轴、Y轴的平移倍数
path属性介绍

定义被绘制的路径

属性 描述
android:name 定义路径名字
android:pathData 定义矢量图的路径信息
android:fillColor 定义填充路径的颜色,没有定义不填充
android:strokeColor 定义路径边框的颜色
android:strokeWidth 定义路径边框的宽度
android:strokeAlpha 定义路径边框颜色的透明度
android:fillAlpha 定义填充路径颜色的透明度
android:trimPathStart、android:trimPathEnd 取值范围都是(0,1),意思是截取从起始部分到结束部分的部分path
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 类似于path中的pathdata,定义路径信息
pathData里面绘制图形的一些基本语法:
  • 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 curveto(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():关闭路径

注意:上述所有指令大小写均可。大写表示绝对定位,参照全局坐标系;小写表示相对定位,参照父容器坐标系。指令和数据间的空格可以省略。同一指令出现多次可以只用一个。

所以刚刚的简单代码的意思是

M50,2 L80.813,2 L80.813,130 L50,130 L50,2 Z
//移动到M(50,2)的位置,并且画了封闭的四根线L(X,Y)... 最后Z:结束绘图
SVG完整例子

icon_vector.xml : 绘图xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="200dp"
    android:height="200dp"
    android:tint="@color/colorAccent"
    android:viewportHeight="24.0"
    android:viewportWidth="24.0">
    <path
        android:name="icon_path"
        android:fillColor="#FF000000"
        android:pathData="M6,18c0,0.55 0.45,1 1,1h1v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L11,19h2v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L16,19h1c0.55,0 1,-0.45 1,-1L18,8L6,8v10zM3.5,8C2.67,8 2,8.67 2,9.5v7c0,0.83 0.67,1.5 1.5,1.5S5,17.33 5,16.5v-7C5,8.67 4.33,8 3.5,8zM20.5,8c-0.83,0 -1.5,0.67 -1.5,1.5v7c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5v-7c0,-0.83 -0.67,-1.5 -1.5,-1.5zM15.53,2.16l1.3,-1.3c0.2,-0.2 0.2,-0.51 0,-0.71 -0.2,-0.2 -0.51,-0.2 -0.71,0l-1.48,1.48C13.85,1.23 12.95,1 12,1c-0.96,0 -1.86,0.23 -2.66,0.63L7.85,0.15c-0.2,-0.2 -0.51,-0.2 -0.71,0 -0.2,0.2 -0.2,0.51 0,0.71l1.31,1.31C6.97,3.26 6,5.01 6,7h12c0,-1.99 -0.97,-3.75 -2.47,-4.84zM10,5L9,5L9,4h1v1zM15,5h-1L14,4h1v1z"
        android:trimPathEnd="1.0"
        android:trimPathStart="0.0" />
</vector>

anim_icon.xml : 定义动画的XML

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="sequentially">
    <objectAnimator
        android:duration="2000"
        android:propertyName="trimPathStart"
        android:valueFrom="0.0"
        android:valueTo="1.0" />
    <objectAnimator
        android:duration="2000"
        android:propertyName="trimPathStart"
        android:valueFrom="1.0"
        android:valueTo="0.0" />
</set>

icon_vector_anim.xml : AnimatedVectorDrawable的XML文件

<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    <!--icon_vector即为要操作的VectorDrawable资源文件-->
    android:drawable="@drawable/icon_vector">
    <target
        <!--target的name,这里为上面VectorDrawable文件里的path名字-->
        android:name="icon_path"
        <!--为目标添加的动画-->
        android:animation="@anim/anim_icon" />

</animated-vector>

布局中使用

<ImageView
        android:id="@+id/iv_anim"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:contentDescription="@string/app_name"
        android:src="@drawable/icon_vector_anim" />
SVG其他DEMO
1 GoogleClock
2 https://github.com/geftimov/android-pathview
3 https://github.com/mcxtzhang/PathAnimView
success.gif
SVG资源、插件推荐

1、通过iconfont获取矢量图

Paste_Image.png

2、安装svgtoandroid插件
File -> Setting -> Plugins -> Browser repositories -> 搜“svg2VectorDrawable” -> 安装并重启Android Studio,再次进来后顶部工具栏会多一个图标:


点击图标弹出对话框:


勾选Batch选项,将对被选中文件夹中的.svg文件进行批量转换。nodpi会自动添加到没有后缀的drawable文件夹中。

  • 手动。新建一个<vector></vector>标签的xml文件,通过观察文件内容,很容易获取到关键信息。width height自然对应<vector/>中宽高,viewBox后两位数字是分别对应<vector/>中的viewportWidth和viewportHeight,往下<path/>中的d的数据的对应<vector/>中<path/>中的pathData。fillColor自己手动设置。

  • 自动


鼠标选中drawable文件夹,右键, New, Vector Asset, Local file,然后出现:

先选本地文件(还能支持PSD,强吧),再到磁盘中找到之前下载的.svg矢量图。导入后可以为文件重命名(建议用svg_或者有区别于其它格式的前缀),默认导入宽高均为24dp,选中Override框则读取文件本来宽高,其它配置视需求而定。点击Next到下一页最后点Finish就导入了。自动导入需要格式化一下就是前面svg_ic_arrow_right.xml的样子了。

3、方法二:Android Studio的Material Icon入口
鼠标选中drawable文件夹,右键, New, Vector Asset,然后出现:

点击机器人进入搜索筛选:


左侧的搜索和分类可以快速索引。这里应该都是由谷歌官方制作的MD标准图标,建议先到这里搜索,如果没有再到网上搜索。

最后注意:

SVG:5.0以下某些机型可能会崩溃的,原因是AppCompatTextView是没有对CompoundDrawable进行适配的,所以我们要判断系统版本如果小于5.0,就用ContextCompat.getDrawable获取到Drawable实例,再setCompoundDrawablesWithIntrinsicBounds。

关于适配有开源的项目:
VectorCompatTextView,轻松compile到项目中使用。还特意添加了一个实用功能——tint
染色——可以选择是否让图标与文字颜色一样,这样就不必关心xml里的fillColor
属性了。用例:

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

推荐阅读更多精彩内容