SVG一种用于描述图像的标记语言。类似HTML。
SVG严格遵从XML语法,并用文本格式的描述性语言来描述图像内容,因此是一种和图像分辨率无关的矢量图形格式。
下面是一个红色三角形的svg示例:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="4cm" height="4cm" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg" version="1.1">
<title>Example triangle01- simple example of a 'path'</title>
<desc>A path that draws a triangle</desc>
<rect x="1" y="1" width="398" height="398" fill="none" stroke="blue" />
<path d="M 100 100 L 300 100 L 200 300 z" fill="red" stroke="blue" stroke-width="3" />
</svg>
效果图如下:
说明:
点击查看svg元素索引列表
在Android中,负责矢量图加载,解析,绘制相关工作的类就是VectorDrawable,通过加载一个基于XML的VectorDrawable文件,在draw方法中把矢量图绘制到Canvas。在Android中矢量图一般用于图标和按钮。
1.这里使用Method Draw先编辑一个svg格式的矢量图,点击打开Method Draw,编辑完成后导出svg格式文件。
heart.svg
<svg height="400" width="580" xmlns="http://www.w3.org/2000/svg">
<!-- Created with Method Draw - http://github.com/duopixel/Method-Draw/ -->
<g stroke="null">
<title>Layer 1</title>
<path d="m218.25,65.499992c31.171158,0 61.067017,21.318344 71.75,50.4375c10.683014,-29.119156 40.610474,-50.4375 71.75,-50.4375c40.546692,0 71.75,32.481865 71.75,75.656258c0,59.348114 -60.477264,105.195892 -143.5,193.34375c-83.022751,-88.131226 -143.5,-133.995636 -143.5,-193.34375c0,-43.174393 31.203293,-75.656258 71.75,-75.656258z" fill="#ff0000" id="svg_1" stroke="#ff0000" stroke-width="1.5" />
</g>
<g>
<title>background</title>
<rect fill="none" height="402" id="canvas_background" width="582" x="-1" y="-1" />
</g>
</svg>
2.把svg文件转换为Android的VectorDrawable文件。
手动转换
1. 在drawable目录下新建一个根节点为<vector>
的xml文件。
2. 把svg文件中的path数据拷贝到<vector>
,比如svg中path的d对应<vector>
中path的android:pathData
,stroke对应android:strokeColor
,stroke-width对应android:strokeWidth
等。
使用工具转换
使用svg2android把svg文件转换为Android Drawable文件,把导出文件放到drawable目录下。
res/drawable/vector_drawable_heart.xml
<?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android" <!-- 图片实际宽高 --> android:width="580dp" android:height="400dp" <!-- 画布的宽高,图像的锚点、坐标都是相对于画布 --> android:viewportWidth="580" android:viewportHeight="400"> <!-- draw a path --> <path android:fillColor="#ff0000" android:pathData="M218.25,65.499992c31.171158,0 61.067017,21.318344 71.75,50.4375c10.683014,-29.119156 40.610474,-50.4375 71.75,-50.4375c40.546692,0 71.75,32.481865 71.75,75.656258c0,59.348114 -60.477264,105.195892 -143.5,193.34375c-83.022751,-88.131226 -143.5,-133.995636 -143.5,-193.34375c0,-43.174393 31.203293,-75.656258 71.75,-75.656258z" android:strokeColor="#ff0000" android:strokeWidth="1.5" /> <path android:pathData="M -1 -1 H 581 V 401 H -1 V -1 Z" /> </vector>
注意:转换工具默认把画布的size作为矢量图的实际宽高,比如一个icon的svg设计时画布的宽高为480*480
,但实际需要的宽高为48*48
,所以记得修改<vector>
中的android:width
和android:height
为实际需要的宽高,不然就比较耗内存。
3.使用矢量图示例
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/vector_drawable_heart" />
目前这种做法只支持Android5.0+,如果想在Android5.0以下正常运行还要做如下兼容处理。
1.在app的build.gradle文件中添加如下配置,启用support库。
android { defaultConfig { vectorDrawables.useSupportLibrary = true }
}
dependencies { compile 'com.android.support:appcompat-v7:23.3.0' }
2.ImageView改为使用support库的AppCompatImageView,使用app:srcCompat
替换android:src
。
<android.support.v7.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/vector_drawable_heart" />
AnimatedVectorDrawable可以让VectorDrawable加上动画效果。
VectorDrawable实现动画效果一般需要3个文件:
<vector>
的xml文件,矢量图。<animated-vector>
的xml文件,矢量图动画定义文件。1.VectorDrawable文件如下,通过android:name属性为group和path定义了一个唯一的名字,在AnimatedVectorDrawable文件中就是通过该名字实现group/path和相关动画的关联。
<!--res/drawable/vector_drawable_cpu.xml-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="128dp" android:height="128dp" android:viewportHeight="600" android:viewportWidth="600">
<group android:name="cpu_box">
<path android:name="cpu" android:fillColor="#000000" android:pathData=" M341.087,157.478 c7.417,0,13.435,6.018,13.435,13.435 v170.174c0,7.417-6.018,13.435-13.435,13.435 H170.913 c-7.417,0-13.435-6.018-13.435-13.435V170.913c0-7.417,6.018-13.435,13.435-13.435H341.087z M390.348,157.478 c0-19.785-16.041-35.826-35.826-35.826H157.479c-19.785,0-35.826,16.041-35.826,35.826v197.043 c0,19.785,16.041,35.826,35.826,35.826h197.043c19.785,0,35.826-16.041,35.826-35.826V157.478z " />
</group>
<group android:name="bottom">
<path android:name="wires_bottom" android:fillColor="#000000" android:pathData=" M193.304,408.261V462h-17.913 v-53.739H193.304z M264.957,408.261V462h-17.914v-53.739H264.957z M300.783,408.261V462h-17.914v-53.739H300.783z M229.13,408.261 V462h-17.913v-53.739H229.13z M336.609,408.261V462h-17.914v-53.739H336.609z" />
</group>
<group android:name="top">
<path android:name="wires_top" android:fillColor="#000000" android:pathData=" M193.304,50v53.739h-17.913V50H193.304z M264.957,50 v53.739h-17.914V50H264.957z M300.783,50v53.739h-17.914V50H300.783z M229.13,50v53.739h-17.913V50H229.13z M336.609,50v53.739 h-17.914V50H336.609z " />
</group>
<group android:name="right">
<path android:name="wires_right" android:fillColor="#000000" android:pathData=" M408.261,318.695H462v17.914h-53.739V318.695z M408.261,247.043H462v17.914h-53.739V247.043z M408.261,211.217 H462v17.913h-53.739V211.217z M408.261,282.869H462v17.914h-53.739V282.869z M408.261,175.391H462v17.913h-53.739V175.391z" />
</group>
<group android:name="left">
<path android:name="wires_left" android:fillColor="#000000" android:pathData=" M50,318.695h53.739v17.914H50V318.695z M50,247.043h53.739v17.914H50V247.043z M50,211.217h53.739v17.913H50V211.217z M50,282.869 h53.739v17.914H50V282.869z M50,175.391h53.739v17.913H50V175.391z" />
</group>
</vector>
效果图如下:
2.属性动画文件的编写,下面是cpu顶部排线的动画文件,还有类似的底部和左右排线的动画文件,共4个动画文件。
<!-- res/animator/pulse_top.xml -->
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator android:propertyName="translateY" android:valueType="floatType" android:valueFrom="0" android:valueTo="-10" android:repeatMode="reverse" android:repeatCount="infinite" android:duration="250" />
</set>
3.AnimatedVectorDrawable文件如下,根节点<animated-vector>
,通过android:drawable
属性设置使用的矢量图文件。<target>
元素中的android:name
对应VectorDrawable文件中group/path的名称,android:animation
设置group/path使用的动画。
<!-- res/drawable/animated_cpu.xml -->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/vector_drawable_cpu">
<target android:name="top" android:animation="@animator/pulse_top" />
<target android:name="right" android:animation="@animator/pulse_right" />
<target android:name="left" android:animation="@animator/pulse_left" />
<target android:name="bottom" android:animation="@animator/pulse_bottom" />
</animated-vector>
4.最后,在AppCompatImageView中使用AnimatedVectorDrawable
<android.support.v7.widget.AppCompatImageView
android:id="@+id/image1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
app:srcCompat="@drawable/animated_cpu" />
使用AnimatedVectorDrawableCompat.create方法加载AnimatedVectorDrawable文件得到AnimatedVectorDrawable对象。
AnimatedVectorDrawableCompat是support库中的类,作用是使AnimatedVectorDrawable兼容Android5.0以下系统。
image1 = (AppCompatImageView) findViewById(R.id.image1);
AnimatedVectorDrawableCompat animatedVectorDrawable = AnimatedVectorDrawableCompat.create(this, R.drawable.animated_cpu);
image1.setImageDrawable(animatedVectorDrawable);
addClickAnimationListener(image1);
点击停止/播放动画
public void addClickAnimationListener(final AppCompatImageView image) {
image.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Drawable animation = image.getDrawable();
if (animation instanceof Animatable) {
Animatable anim = (Animatable) animation;
if (anim.isRunning()) {
// 停止动画
anim.stop();
} else {
// 播放动画
anim.start();
}
}
}
});
}
动画效果如下:
注意:目前AnimatedVectorDrawableCompat在Android5.0以下不支持pathData类型属性动画。如果需要用到pathData类型属性动画可以通过以下方法做兼容处理。
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
// 在android5.0+下执行下面代码
}
这里给VectorDrawable的path添加一个透明度动画,发现没有效果,日志打印如下:
W/PropertyValuesHolder: Method setAlpha() with type int not found on target class class android.support.graphics.drawable.VectorDrawableCompat$VGroup W/PropertyValuesHolder: Method setRotation() with type float not found on target class class android.support.graphics.drawable.VectorDrawableCompat$VFullPath
日志中可以看出没有找到相关的set方法,属性动画的实现原理其实是通过java中的反射找到相关set方法去动态修改属性值实现的。
VectorDrawable(这里使用的是VectorDrawableCompat,兼容Android5.0以下版本)的group对应的类是VectorDrawableCompat$VGroup
,path对应的类是VectorDrawableCompat$VFullPath
。
通过查看VectorDrawableCompat$VFullPath
代码发现,VFullPath中透明度属性的名称为fillAlpha,于是把android:propertyName
值由alpha
改为fillAlpha
就可以了。
<objectAnimator android:duration="1500" android:propertyName="fillAlpha" android:valueFrom="1" android:valueTo="0" android:valueType="floatType" />
示例代码工程地址:https://coding.net/u/linchaolong/p/AndroidSvgExample/git
VectorDrawable和AnimatedVectorDrawable的一个兼容库,目前支持api 14+。
Github地址:https://github.com/wnafee/vector-compat
点击查看详细介绍
AndroidSVG是Android下的SVG解析、渲染库。目前几乎完全支持SVG 1.1的静态可视元素和SVG 1.2小部分规范(filters除外)。支持API 8+。
支持svg格式矢量图的ImageView
<com.caverock.androidsvg.SVGImageView
xmlns:svg="http://schemas.android.com/apk/res-auto"
android:layout_width="100dp"
android:layout_height="50dp"
svg:svg="filename.svg"/>
android-pathview是绘制路径的动画库,路径可来自于svg或者标准Paths,使svg或path具有动画效果,并且可以改变路径的颜色、宽度。
Github地址:https://github.com/geftimov/android-pathview
点击查看详细介绍
Android4.4以后AnimatedVectorDrawable可以让两个SVG图像无缝过渡(称为变形动画),但是这两个svg图像的path必须参数个数要相等,同时这些参数的类型要匹配(也就是说格式要对齐),如果不对齐会产生异常。简单的path可以手动修改对齐,但是复杂点的就比较难了。这个工具就是通过命令行的方式将任意两个svg资源转换成对齐的模式,而不会改变原始图像的外观。
Githu地址:https://github.com/bonnyfone/vectalign
点击查看详细介绍