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"/>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容