1. 初识矢量图SVG与VectorDrawable
位图:有一个一个像素点组成的,放大会失真
矢量图:实际是一条path路径,每一个像素点是根据GPU实时计算出来,放大缩小不会失真
SVG和Vector的区别:
SVG,即Scalable Vector Graphics 矢量图,这种图像格式在前端中已经使用的非常广泛了,详见WIKI:https://en.wikipedia.org/wiki/Scalable_Vector_Graphics
Vector,在Android中指的是Vector Drawable,也就是Android中的矢量图,详见: https://developer.android.com/reference/android/graphics/drawable/VectorDrawable.html
SVG:通常在前端中使用,是一套语法规范,GPU根据该规范绘制图片。SVG中会有很多标签用于绘制图片,如:rest、circle、polyline、line、path等。
Vector:通常在Android中使用,只实现了SVG语法中的path标签,可以视为简单化的矢量图。
SVG在加载过程中,效率比较低,而android的Vector只采用了SVG的path标签,如此设计就是为了提高SVG加载的效率
首先我们看一下位图、SVG图和 Vector图片之间的一个大小关系
同样一张图片,PNG格式的5.6K,而SVG的2.6K,经过压缩后的Vector格式的图片只有1.5K,这是实用 Vector图片的第二个好处,除了支持随意放大缩小之外,还极大减小占用体积。
Vector常用语法了解:
Vector中利用不同字母来代表不同含义,实现图片的绘制,下面我们简单看一下这三个指令:
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():关闭路径
上面的指令看着都很好理解,了解了上面的指令用法,基本就可以绘制常见的SVG图片了。。。
下面看一个简单的例子
Vector中,android :width和 android :height就是图片在手机上显示的大小, android :viewportWidth和 android :viewportHeight可以理解为,我门把图片分成了 500* 500的小等分,我们在绘制时,以500为基线坐标,在这些坐标上绘制图片,显示图片时,不管图片多大,基线坐标是不变的,这是SVG格式图片不失真的主要原因; android :fillColor自然是绘制图片的颜色,最重要的就是 android :pathData了, Vector就是根据 pathData来绘制路径的。
有些人会觉得,简单图形手写 pathData还行,可是比较复杂的图形怎么办呢,当然有绘制工具了,这里介绍一个SVG Editor:http://editor.method.ac/,我们可以在这行面绘制复杂的数量图形,然后导出SVG格式的图像,而android中无法直接使用SVG格式的图,所以我们可以通过 http://inloop.github.io/svg2android/来进行SVG到Vector的转化,是不是很方便呢。。
2. VectorDrawable兼容性问题
VectorDrawable是在android L中提出来的,也就是说VectorDrawable只兼容minSDK>=21的版本,这个限制是非常大的,我们知道,目前市面上的Android版本比较混乱,各种版本的android手机都存在,这就导致VectorDrawable系统兼容性非常差。
VectorDrawable可以为我们的应用带来很多好处,Google也非常重视VectorDrawable的发展,后来在Gradle Plugin1.5中,Google为VectorDrawable做了兼容,主要实现是这样的:
当手机设备系统版本>=21 —> 实用Vector
当手机设备系统版本<21 —->将Vector转化为PNG格式显示,而这一步转化是在编译时自动完成的
我们可以看出来,这种兼容实际上并不好,既增加了兼容的成本,效果上也做了很多限制,Vector图片可以做很多动画(后面会讲),这些效果在21版本以下就没法使用。
而VectorDrawable真正的春天要等到AppCompat23.2的到来,Google在AppCompat23.2中增加了VectorDrawable全版本兼容,它使得静态的VectorDrawable可以支持到android2.1+,而动态的VectorDrawable可以支持到android3.0+的设备,这两个版本几乎已经包含了市面上90%+的android手机设备。
3. Android studio中如何使用 VectorDrawable
Android studio中提供了一个Vector Asset工具,可以很方便的使用矢量图,通过File->New-> Vector Asset打开,打开界面如图:
我们可以选择Material Icon来看studio为我们提供的大量 Vector的Icon供我们去实用,当然也可以通过Local File来导入我们自定义的SVG Icon。 当我们选择好Icon后,点击next->finish, studio会在drawable下为我们创建相应的 Vector文件。
那么自定义的Icon是怎么来的呢,我们一般的开发者是无法熟练的制作SVG的图片,一般这些Icon是由设计师给我们制作好的,可是对于个人开发者而言,没有这种条件,那我我们可以通过 http://iconfont.cn/来下载我们所需要的SVG的Icon,这是阿里巴巴为我们提供的图标库,里面的Icon还是比较丰富的。
3.1 静态的VectorDrawable
在 studio使用 Vector之前,我们首先需要设置gradle的配置,使得我们的项目支持 VectorDrawable,我们打开项目的build.gradle文件,在 android标签的 defaultConfig标签中增加一行 vectorDrawables.useSupportLibrary = true 的配置,这样我们的项目就可以使用 VectorDrawable了,前面也提到了 VectorDrawable的兼容性问题,我们需要在dependencies标签中引用 AppCompat23.2+的版本来使得 Vector 支持多版本,通常我们创建项目时, studio会自动为我们引入最新的 AppCompat版本,这点我们可以不用自己去配置。
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
dependencies {
compile 'com.android.support:appcompat-v7:25.3.1’
}
在控件中使用 VectorDrawable其实很简单,我们可以把 VectorDrawable当作一个普通的PNG图像来使用。
在ImageView/ImageButton中,我们只需要将android:src改变为app:srcCompat=“@drawable/vector_image”即可。
例如我们有一个名字 为 ic_face_black_24dp .x ml的 VectorDrawable图像,要把他使用在ImageView中来,我们引入代码如下:
这样,我们就可以在ImageView中显示一个静态的 VectorDrawable, ImageView的宽高指定任意值, Vector图片都不会失真。这里有个地方需要注意,我们的Activity需要继承 AppCompatActivity才可以正常显示 VectorDrawable。
在Button中,我们通过 app :srcCompat 设置 Vector图片作为背景时,会发现不起作用,Google的解释是像Button这样带有状态的控件,我们不可以直接使用 app :srcCompat来设置背景图片,但是,可以通过 selector 来设置不同点击态的背景
如我们创建了一个 bt_bg_vector.xml的 selector:
此时,我们在 Button中引用 bt_bg_vector.xml作为点击态的背景,代码如下:
如此,我们就可以方便的在ImageView、ImageButton、 Button中设置静态的 VectorDrawable,是不是跟png图片使用差别不大。
3.2 动态的VectorDrawable
前面我们看到了 VectorDrawable的一些优势,比如:体积小、支持任意放大缩小等,但这并不足以让开发者放弃位图而转向 VectorDrawable,下面我们来看一下 VectorDrawable又一个惊天大优势,可以方便的使用动画。
在 VectorDrawable中要使用属性动画,我们需要使用animated-vector, animated-vector其实也是一个XML文件,我们可以理解为配置动画的粘合剂, animated-vector将我们的目标 VectorDrawable图像和所需要的属性动画animator进行了连接。
animated-vector代码如下所示:
其中android :drawable 是VectorDrawable图片名称 ,android :name 是对应 VectorDrawable中group的name(group后面再介绍), android :animation 是要移动的属性动画, animated-vector标签在现在的Android Studio中实际上是会报错的,但这个并不影响编译和运行,属于Android Studio的Bug。
ic_thumbs_up_down_black_24dp 代码如下:
因为属性动画要改变绘制的图片属性来实现动画,可是path标签中并没有这种属性,因此,VectorDrawable要想使用属性动画,就需要用group标签来封装path标签,将属性动画作用在group标签中, 这里使用group标签将 vector图片分成了两组,如果图片比较复杂,会将其分成多组。
上面准备工作做好后,就可以在我们代码中直接使用了,使用也和普通 Vector 图片一样,如下:
这样,我们在Activity中直接调用改属性动画,使它运行就OK了。
arrow = (ImageView) findViewById(R.id.arrow);
Drawable drawable = arrow.getDrawable();
if(drawable instanceof Animatable){
((Animatable)drawable).start();
}
这只是一个简单的属性动画例子,我们可以类似的实现更多复杂的动画效果。。。
3.3 VectorDrawable打造路径动画
这个搜索框的动画我们在很多地方都见过,如果使用普通的绘制动画去实现,还是有一定难度的,可是利用VectorDrawable来实现这种动画效果将非常容易只需要几行代码就可以搞定。
下面是一个searchbar的 VectorDrawable,xml如下:
这其实就是我们android应用中常见的搜索框,我们将这个Vector分为两个path,一个path就是一个放大镜的图标,另外一个就是一条直线,那么我们现在需要给这个 searchbar一个动画效果,但我们并不需要对图片进行平移、缩放或变色这种基本的动画,我们需要改变这个图片的路径, VectorDrawable给我们提供了这种比较绚丽的动画效果,那就是 trimPathStart 属性。 trimPathStart 属性可以模拟 Vector图片的路径生成,就像人拿了一个画笔,一点一点绘制出我们这个图片一样。 trimPathStart 的使用和属性动画其它属性的使用相同,属性动画文件如下anim_bar.xml:
trimPathStart 代表绘制路径, valueFrom= “0" valueTo= "1" 代表线条bar从无到有开始绘制。 跟 anim_bar.xml相似,我们只给线条设置了动画,还需要给search图标设置动画,设置方式和 anim_bar.xml几乎相同,命名为 anim_search.xml。
我们设置好这个属性动画后,就可以 animated-vector中直接使用这个属性动画,将该动画和我们的 searchbar图片结合, animated-vector的xml文件如下searchbar_anim.xml:
这样,我们就可以在Image中直接使用searchbar_anim,来实现我们的搜索动画了。
在activity中使用如下代码开始动画:
if(searchBar.getDrawable() instanceof Animatable){
((Animatable)searchBar.getDrawable()).start();
}
学好VectorDrawable,我们可以很方便的实现许多较复杂的动画效果,今天就先介绍这么多了。。。。
项目gitHub地址:https://github.com/gjnm/AndroidDraw