SVG,即Scalable Vector Graphics 可伸缩矢量图形。这种图像格式在前端中已经使用的非常广泛,而在移动端的开发中,遇到一些复杂的自定义控件或者动画效果,我们就可以考虑使用SVG。
1.矢量图像:SVG是W3C 推出的一种开放标准的文本式矢量图形描述语言,他是基于XML的专门为网络而设计的图像格式
SVG是一种采用XML来描述二维图形的语言,所以它可以直接打开xml文件来修改和编辑。
2.位图图像:位图图像的存储单位是图像上每一点的像素值,因而文件会比较大,像GIF、JPEG、PNG等都是位图图像格式。
在Android中,SVG的实现方式就是Vector Drawable。这是个在5.0时增加的新类,所以对之前版本的兼容会有些问题。相对于普通的Drawable来说,Vector Drawable有以下几个好处:
(1)Vector图像可以自动进行适配,不需要通过分辨率来设置不同的图片。
(2)Vector图像可以大幅减少图像的体积,同样一张图,用Vector来实现,可能只有PNG的几十分之一。
(3)使用简单,很多设计工具,都可以直接导出SVG图像,从而转换成Vector图像,功能强大。
(4)不用写很多代码就可以实现非常复杂的动画。
Vector Drawable实际上是一个XML文件,咱们先来看一个vector的例子
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="400dp"
android:height="400dp"
android:viewportHeight="400"
android:viewportWidth="400">
<path
android:pathData="M 100 100 L 300 100 L 200 300 z"
android:strokeColor="#000000"
android:strokeWidth="5"
android:fillColor="#FF0000"
/>
vector>
这个vector画了一个三角形,可以从Android Studio的preview功能栏里预览,如下图:
对照着上面的代码,咱们来学习Vector Drawable的基本语法。这些语法开发者不需要全部精通,只要能够看懂,这些path标签及数据生成都可以交给工具来实现。
1.pathData标签
先看pathData标签,这里定义了vector中path的绘制,也是最重要的一部分。注意’M’处理时,只是移动了画笔, 没有画任何东西。语法如下:
M = moveto(M X,Y) :将画笔移动到指定的坐标位置,相当于 android Path 里的moveTo()
L = lineto(L X,Y) :画直线到指定的坐标位置,相当于 android Path 里的lineTo()
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):弧线 ,相当于arcTo()
Z = closepath():关闭路径(会自动绘制链接起点和终点)
2.path标签
path标签的内容:
android:name 定义该 path 的名字,这样在其他地方可以通过名字来引用这个路径
android:pathData 和 SVG 中 d 元素一样的路径信息。
android:fillColor 定义填充路径的颜色,如果没有定义则不填充路径
android:strokeColor 定义如何绘制路径边框,如果没有定义则不显示边框
android:strokeWidth 定义路径边框的粗细尺寸
android:strokeAlpha 定义路径边框的透明度
android:fillAlpha 定义填充路径颜色的透明度
android:trimPathStart 从路径起始位置截断路径的比率,取值范围从 0 到1
android:trimPathEnd 从路径结束位置截断路径的比率,取值范围从 0 到1
android:trimPathOffset 设置路径截取的范围
android:strokeLineCap 设置路径线帽的形状,取值为 butt, round, square.
android:strokeLineJoin 设置路径交界处的连接方式,取值为 miter,round,bevel.
android:strokeMiterLimit 设置斜角的上限
3.vector标签
根元素 vector标签是用来定义这个矢量图的,该元素包含如下属性:
android:name 定义该drawable的名字
android:width 定义该 drawable 的内部(intrinsic)宽度,支持所有 Android 系统支持的尺寸,通常使用 dp
android:height 定义该 drawable 的内部(intrinsic)高度,支持所有 Android 系统支持的尺寸,通常使用 dp
android:viewportWidth 定义矢量图视图的宽度,视图就是矢量图 path 路径数据所绘制的虚拟画布
android:viewportHeight 定义矢量图视图的高度,视图就是矢量图 path 路径数据所绘制的虚拟画布
android:tint 定义该 drawable 的 tint 颜色。默认是没有 tint 颜色的
android:tintMode 定义 tint 颜色的 Porter-Duff blending 模式,默认值为 src_in
android:autoMirrored 设置当系统为 RTL (right-to-left) 布局的时候,是否自动镜像该图片。比如 阿拉伯语。
android:alpha 该图片的透明度属性
4.group标签
有时候我们需要对几个路径一起处理,这样就可以使用 group 元素来把多个 path 放到一起。 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 值来指定的。
通过上面的属性可以看出, group 主要是用来设置路径做动画的关键属性的.
上面的这些语法只要能看懂就可以了。我们会用一些成熟的工具来辅助SVG在移动端的开发。
1.先说美工,SVG图一般直接让美工来帮你搞定就行了!像PS、Illustrator等等都支持导出SVG图片
2.获取到SVG图片后,我们要将其转换为vector drawable对象,这款插件svgtoandroid 用过都说好。
安装:File -> Setting -> Plugins -> Browser repositories -> 搜“svg2VectorDrawable” -> 安装并重启Android Studio,再次进来后顶部工具栏会多一个图标:
点击图标弹出对话框:
点击Generate就行了。勾选Batch选项,将对被选中文件夹中的.svg文件进行批量转换,这就是转换之后的效果:
3.如果没有SVG图片怎么办?可以使用SVG编辑器来进行SVG图像的创作和编写。
4.使用AndroidStudio自带的工具完成SVG添加,AS会自动生成兼容性图片(高版本会生成xxx.xml的SVG图片;低版本会自动生成xxx.png图片)。具体过程看Vector Asset Studio的使用
5.最后分享几个可以获取SVG资源的网站
http://www.shejidaren.com/8000-flat-icons.html
http://www.flaticon.com/
http://www.iconfont.cn/plus
由于vector drawable是5.0之后才出来的东西,所以我们需要对之前的版本进行兼容。假设大家都使用Android Studio 2.2以上的版本,并且gradle版本在2.0以上。下面是配置的步骤:
1、添加
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
2、添加
compile ‘com.android.support:appcompat-v7:25.3.1’//这里具体看自己的版本
3、项目的Activity中都包含(通用做法是在BaseActivity中加):
static { AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}
Vector Drawable可以理解为一张图片,所以能设置到其他的控件之中。
1.ImageView、ImageButton、AppCompatImageView(这是继承自ImageView用于5.0以下加载矢量图的控件)
xml中使用属性 app:srcCompat(5.0以上可以直接使用background或src)
代码里面使用无区别,直接setBackground即可。
2.Button
不支持app:srcCompat
直接使用
3.RadioButton
直接使用
4.textview的drawable
直接使用,5.0以下某些机型可能会崩溃的。
AppCompatTextView是没有对CompoundDrawable进行适配的,所以需要自己动手才能丰衣足食。简单原理是,判断系统版本如果小于5.0,就用ContextCompat.getDrawable获取到Drawable实例,再setCompoundDrawablesWithIntrinsicBounds。
去阿里svg平台随便找张svg的图片,既可以通过svgtoandroid
也可以通过AS自带的插件将其转化为vector drawable,接着配置项目兼容环境,再将这个vector在资源xml中用android:src赋值给ImageView,最后的结果就是这样,无论怎样放大都不会失真。
除了帧、补间、属性动画以外,vector drawable也可以用来完成动画效果,还记得之前讲的path标签吗,这里面的属性都可以作为动画的变化条件,我们再展示一下:
android:name 定义该 path 的名字,这样在其他地方可以通过名字来引用这个路径
android:pathData 和 SVG 中 d 元素一样的路径信息。
android:fillColor 定义填充路径的颜色,如果没有定义则不填充路径
android:strokeColor 定义如何绘制路径边框,如果没有定义则不显示边框
android:strokeWidth 定义路径边框的粗细尺寸
android:strokeAlpha 定义路径边框的透明度
android:fillAlpha 定义填充路径颜色的透明度
android:trimPathStart 从路径起始位置截断路径的比率,取值范围从 0 到1
android:trimPathEnd 从路径结束位置截断路径的比率,取值范围从 0 到1
android:trimPathOffset 设置路径截取的范围
android:strokeLineCap 设置路径线帽的形状,取值为 butt, round, square.
android:strokeLineJoin 设置路径交界处的连接方式,取值为 miter,round,bevel.
android:strokeMiterLimit 设置斜角的上限
首先,获取到一张vector图片,比如这次使用的是一个对勾。我们给path标签附上了name属性,这是为了之后在动画中找到这条path。
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:name="path_check"
android:fillColor="#FF000000"
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
vector>
接着,用动画vector包装原来的vector图片,其创建方式和vector相似,只不过最外层的标签为animated-vector。我们还要为target标签赋值,name属性是前面命名的、vector中需要变化的地方,而animation自然就是属性动画了。
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:drawable="@drawable/vector_check"
tools:targetApi="lollipop">
<target
android:name="path_check"
android:animation="@anim/check_anim"/>
animated-vector>
归根结底还是需要用到属性动画,我们通过xml的方式来完成它。注意要在res下创建anim文件夹,再将xml放入其中。这里变化的属性是path标签中trimPathEnd属性。
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="500"
android:propertyName="trimPathEnd"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType"/>
set>
最后,只要在代码中将Drawable转化为Animatable,并调用其start()方法开启动画即可。
<ImageView
android:id="@+id/img"
android:layout_width="240dp"
android:layout_height="240dp"
android:src="@drawable/anim_vector"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Animatable animatable = (Animatable) imageView.getDrawable();
animatable.start();
}
});
来看看效果图吧
先上图:
简单说一下思路
第一步 下载含有中国地图的 SVG
这里附一个地图资源: https://www.amcharts.com/dl/javascript-maps/ ,这里面包含世界各个国家的SVG地图,各个省份地图
第二步 将 SVG 资源转换成相应的 Android 代码
第三步 利用 Xml 解析 SVG 的代码 封装成 JavaBean 最重要的得到 Path
利用 Xml 解析,把中国地图的 Path 封装成一个个省的 JavaBean。
第四步 重写 OnDraw 方法 利用 Path 绘制中国地图
第五步 重写 OnTouchEvent 方法,记录手指触摸位置,判断这个位置是否坐落在某个省份上
具体实现我们下一篇博客再讲吧,这里贴一下前面部分的代码地址:
点击下载源码