VectorDrawable矢量图

AndroidL中有一个非常好的新特性是VectorDrawable以及相关的一些类,他们为我们提供了添加复杂矢量图形的强大功能,同时也提供了动画显示这些图形的方法,不用写很多代码就可以实现非常复杂的动画。矢量图形的好处是放大不会失真,可以适应不同分辨率的屏幕。简单的来说,矢量图形就是使用几个形状的方式来描述一个图像元素。矢量图形非常适合于与设备无关的简单或者合成的制图或者不需要实现真实感的场合。而位图(Bitmap ),则完全相反,位图是定义每一个像素点的颜色来显示一张图片,它适合显示一张真实的照片。矢量图形的一大好处是它的渲染是在运行时开始的,因此它可以自适应不同的屏幕。由于矢量图其实保存的只是描述几何图形的文本,因此它只占用非常少的空间。Android 默认的小机器人图标svg格式的2265字节,但是如果我们将它转换成500 x 500的bitmap文件,保存成png格式,则有13272 字节。并且它可以自动伸缩为任意大小的图片,而位图就需要使用多张才能达到不同分辨率的效果。

svg的源码 (https://www.w3.org/TR/SVG/paths.html)




<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="500px" height="500px" viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve">
<g id="max_width__x2F__height" display="none">
<path display="inline" d="M499.001,1v498H1V1H499.001 M500.001,0H0v500h500.001V0L500.001,0z"/>
g>
<g id="androd">
<path fill="#9FBF3B" d="M301.314,83.298l20.159-29.272c1.197-1.74,0.899-4.024-0.666-5.104c-1.563-1.074-3.805-0.543-4.993,1.199L294.863,80.53c-13.807-5.439-29.139-8.47-45.299-8.47c-16.16,0-31.496,3.028-45.302,8.47l-20.948-30.41c-1.201-1.74-3.439-2.273-5.003-1.199c-1.564,1.077-1.861,3.362-0.664,5.104l20.166,29.272c-32.063,14.916-54.548,43.26-57.413,76.34h218.316C355.861,126.557,333.375,98.214,301.314,83.298"/>
<path fill="#FFFFFF" d="M203.956,129.438c-6.673,0-12.08-5.407-12.08-12.079c0-6.671,5.404-12.08,12.08-12.08c6.668,0,12.073,5.407,12.073,12.08C216.03,124.03,210.624,129.438,203.956,129.438"/>
<path fill="#FFFFFF" d="M295.161,129.438c-6.668,0-12.074-5.407-12.074-12.079c0-6.673,5.406-12.08,12.074-12.08c6.675,0,12.079,5.409,12.079,12.08C307.24,124.03,301.834,129.438,295.161,129.438"/>
<path fill="#9FBF3B" d="M126.383,297.598c0,13.45-10.904,24.354-24.355,24.354l0,0c-13.45,0-24.354-10.904-24.354-24.354V199.09c0-13.45,10.904-24.354,24.354-24.354l0,0c13.451,0,24.355,10.904,24.355,24.354V297.598z"/>
<path fill="#9FBF3B" d="M140.396,175.489v177.915c0,10.566,8.566,19.133,19.135,19.133h22.633v54.744
c0,13.451,10.903,24.354,24.354,24.354c13.451,0,24.355-10.903,24.355-24.354v-54.744h37.371v54.744c0,13.451,10.902,24.354,24.354,24.354s24.354-10.903,24.354-24.354v-54.744h22.633c10.569,0,19.137-8.562,19.137-19.133V175.489
H140.396z"/>
<path fill="#9FBF3B" d="M372.734,297.598c0,13.45,10.903,24.354,24.354,24.354l0,0c13.45,0,24.354-10.904,24.354-24.354V199.09c0-13.45-10.904-24.354-24.354-24.354l0,0c-13.451,0-24.354,10.904-24.354,24.354V297.598z"/>
g>
svg>

矢量图详细介绍

1、支持的指令:
M = moveto 相当于 android Path 里的moveTo(),用于移动起始点
L = lineto 相当于 android Path 里的lineTo(),用于画线
H = horizontal lineto 用于画水平线
V = vertical lineto 用于画竖直线
C = curveto 相当于cubicTo(),三次贝塞尔曲线
S = smooth curveto 同样三次贝塞尔曲线,更平滑
Q = quadratic Belzier curve quadTo(),二次贝塞尔曲线
T = smooth quadratic Belzier curveto 同样二次贝塞尔曲线,更平滑
A = elliptical Arc 相当于arcTo(),用于画弧
Z = closepath 相当于closeTo(),关闭path
2、使用原则:
①坐标轴为以(0,0)为中心,X轴水平向右,Y轴水平向下。
②所有指令大小写均可。大写绝对定位,参照全局坐标系;小写相对定位,参照父容器坐标系
③指令和数据间的空格可以省略
④同一指令出现多次可以只用一个
注意,’M’处理时,只是移动了画笔, 没有画任何东西。 它也可以在后面给出上同时绘制不连续线。
3、详细指令分析
3.1、L H V指令
绘制直线的指令是“L”,从当前点划线到给定点。 “L”之后的参数是一个点坐标,如“L 200 400”。 如果画水平线或垂直线,可以使用“H”和“V”指令,后面的参数是x(H指令)或y坐标(V指令)。
M 起点X,起点Y L(直线)终点X,终点Y H(水平线)终点X V(垂直线)终点Y
如:M 10,20 L 80,50 M 10,20 V 50 M 10,20 H 90
VectorDrawable矢量图_第1张图片
3.2、A指令
允许不闭合。可以想像成是椭圆的某一段,共七个参数
A RX,RY,XROTATION,FLAG1,FLAG2,X,Y
RX,RY指所在椭圆的半轴大小
XROTATION指椭圆的X轴与水平方向顺时针方向夹角,可以想像成一个水平 的椭圆绕中心点顺时针旋转XROTATION的角度。
FLAG1只有两个值,1表示大角度弧线,0为小角度弧线。
FLAG2只有两个值,确定从起点至终点的方向,1为顺时针,0为逆时针
X,Y为终点坐标。
M 20,50 A 30,30,0,1 0 80,50 这个就是画一个下半圆。
3.3 C指令 三次贝塞尔曲线。相关博客很多,不在追述。

我们把刚才svg的源码整理成Android的VectorDrawable:
创建一个androidvector.xml内容如下:


<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:viewportWidth="500"
    android:viewportHeight="500"
    android:width="500px"
    android:height="500px">
    <group android:name="android">
    <group android:name=" head _android">
            <path
                android:name="head"
       android:fillColor="#9FBF3B"                        android:pathData="M301.314,83.298l20.159-29.272c1.197-1.74,0.899-4.024-0.666-5.104c-1.563-1.074-3.805-0.543-4.993,1.199L294.863,80.53c-13.807-5.439-29.139-8.47-45.299-8.47c-16.16,0-31.496,3.028-45.302,8.47l-20.948-30.41c-1.201-1.74-3.439-2.273-5.003-1.199c-1.564,1.077-1.861,3.362-0.664,5.104l20.166,29.272c-32.063,14.916-54.548,43.26-57.413,76.34h218.316C355.861,126.557,333.375,98.214,301.314,83.298" />
     group>
    <group android:name="left_eye _android">
            <path
                android:name="left_eye"
                android:fillColor="#FFFFFF"
              android:pathData="M203.956,129.438c-6.673,0-12.08-5.407-12.08-12.079c0-6.671,5.404-12.08,12.08-12.08c6.668,0,12.073,5.407,12.073,12.08C216.03,124.03,210.624,129.438,203.956,129.438" />
    group>
    <group android:name=" right_eye _android">
            <path
                android:name="right_eye"
                android:fillColor="#FFFFFF"
              android:pathData="M295.161,129.438c-6.668,0-12.074-5.407-12.074-12.079c0-6.673,5.406-12.08,12.074-12.08c6.675,0,12.079,5.409,12.079,12.08C307.24,124.03,301.834,129.438,295.161,129.438" />
    group>
    <group android:name=" left_arm _android">
            <path
                android:name="left_arm"
                android:fillColor="#9FBF3B"
              android:pathData="M126.383,297.598c0,13.45-10.904,24.354-24.355,24.354l0,0c-13.45,0-24.354-10.904-24.354-24.354V199.09c0-13.45,10.904-24.354,24.354-24.354l0,0c13.451,0,24.355,10.904,24.355,24.354V297.598z" />
    group>
    <group android:name=" body _android">
            <path
             android:name="body"
                android:fillColor="#9FBF3B"
              android:pathData="M140.396,175.489v177.915c0,10.566,8.566,19.133,19.135,19.133h22.633v54.744c0,13.451,10.903,24.354,24.354,24.354c13.451,0,24.355-10.903,24.355-24.354v-54.744h37.371v54.744c0,13.451,10.902,24.354,24.354,24.354s24.354-10.903,24.354-24.354v-54.744h22.633c10.569,0,19.137-8.562,19.137-19.133V175.489H140.396z" />
    group>
    <group android:name=" right_arm _android">
            <path
                android:name="right_arm"
                android:fillColor="#9FBF3B"
              android:pathData="M372.734,297.598c0,13.45,10.903,24.354,24.354,24.354l0,0c13.45,0,24.354-10.904,24.354-24.354V199.09c0-13.45-10.904-24.354-24.354-24.354l0,0c-13.451,0-24.354,10.904-24.354,24.354V297.598z" />
    group>
    group>
vector>

虽然有对path 规则的绘制教程,但是要创造出现有安卓中各种图标的效果是很难的,要让VectorDrawable有实际价值,肯定不能让开发者去想办法实现这些图形的绘制。
VectorDrawable还可以用来制作动画,动态Vector才是Android Vector Drawable的精髓所在,那么我们就有了个新的名词叫AnimatedVectorDrawable,AnimatedVectorDrawable可以让VectorDrawable动起来,AnimatedVectorDrawable通过改变VectorDrawable的属性来让VectorDrawable呈现动画效果,其实现实际上是试用了属性动画。
通常定义一个AnimatedVectorDrawable需要以下三个xml文件:
1.vector drawable本身:res/drawable/中定义一个有元素的xml文件,参考上面对VectorDrawable的定义。
2.vector drawable的动画文件(Animated vector drawable):res/drawable/中定义一个有元素的xml文件。
3.一个或者多个属性动画文件:res/drawable/中定义一个有元素的xml文件。
Animated vector drawable可以让和元素的属性动态变化。定义一组path或者子group,而元素定义需要绘制的路径。当你想让VectorDrawable呈现动画效果,在定义VectorDrawable的时候需要为group和path的android:name属性设置一个唯一的名字,以便在Animated vector drawable中找到它们。
接下来我们就让小机器人跳舞。
创建动画shrug.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>

创建一个android_anim.xml文件


<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/androidvector">

    <target
        android:animation="@anim/shrug"
        android:name=" left_arm _android " />

    <target
        android:animation="@anim/shrug"
        android:name=" right_arm _android " />
animated-vector>

如果运行现在的代码,我们只能看到静态的图片。这是因为我们需要手动调用播放动画。

 ImageView androidImageView = (ImageView) findViewById(R.id.android);
    Drawable drawable = androidImageView.getDrawable();
    if (drawable instanceof Animatable) {
       ((Animatable) drawable).start();
    }

VectorDrawable矢量图_第2张图片

接下来我们再看一个例子:

viewportWidth:定义图像被划分的比例大小,例如例子中的500,即把500px大小的图像划分成500份,后面Path标签中的坐标,就全部使用的是这里划分后的坐标系统。
star_img.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:viewportHeight="500"
    android:viewportWidth="500"
    android:width="500px"
    android:height="500px">
    <group android:scaleX="5.0" android:scaleY="5.0">
        <path
            android:name="star"
            android:strokeColor="#FF b64f9e"
            android:strokeWidth="2"
            android:pathData="
M 50.0,90.0 L 82.9193546357,27.2774101308                          L 12.5993502926,35.8158045183 L 59.5726265715,88.837672697 L76.5249063296,20.0595700732 L 10.2916450361,45.1785327898
L 68.5889268818,85.4182410261 L 68.5889268818,14.5817589739 L10.2916450361,54.8214672102
L 76.5249063296,79.9404299268 L 59.5726265715,11.162327303 L12.5993502926,64.1841954817
L 82.9193546357,72.7225898692 L 50.0,10.0 L 17.0806453643,72.7225898692
L 87.4006497074,64.1841954817 L 40.4273734285,11.162327303 L23.4750936704,79.9404299268
L 89.7083549639,54.8214672102 L 31.4110731182,14.5817589739 L31.4110731182,85.4182410261
L 89.7083549639,45.1785327898 L 23.4750936704,20.0595700732 L40.4273734285,88.837672697
L 87.4006497074,35.8158045183 L 17.0806453643,27.2774101308 L50.0,90.0Z" />
    group>
vector>

path.xml


<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="together"
    android:duration="2000"
    android:repeatMode="reverse"
    android:repeatCount="1">
<objectAnimator 
    android:propertyName="trimPathEnd" //这里也可以用"trimPathStart"
    android:valueFrom="0"
    android:valueTo="1"
    android:duration="2000"
    android:valueType="floatType"
    android:interpolator="@android:interpolator/linear">

objectAnimator>
<objectAnimator
        android:duration="2000"
        android:propertyName="strokeColor"
        android:valueFrom=" #ff4f65b6"
        android:valueTo="#ff 6cb64f " 
/>
set>
star_anim.xml:

<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/star_img">

    <target
        android:animation="@animator/path"
        android:name="star" />

animated-vector>

从一张图片过渡到另外一张图片:
square.xml:

 
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:viewportWidth="500"
    android:viewportHeight="500"
    android:width="500px"
    android:height="500px">

    <path android:name="square"
        android:fillColor="#ff 00ff00"
        android:pathData="M100,100 L400,100 L400,400 L100,400 z" />

vector>
  animated_square.xml:


<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" 
    android:drawable="@drawable/square">
    <target
        android:animation="@animator/to_triangle"
        android:name="square" />
animated-vector>

现在到了关键部分-Animator自身。我们要实现将正方形向三角形动画过度。实现的方法是将开始值和结束值定义成两个不同的path。起始path是正方形(上面已经定义),结束path是三角形。
必须记住起始和结束path的参数个数要相等,同时这些参数的类型要匹配。我们的正方形path是由move命令(M开头表示move)开始,然后是3个line命令,和最后的关闭命令组成的,因此三角形也必须符合这个模式。但是三角形只需要三条线,而正方形是四条线,因此我们需要一点技巧。我们将正方形上边的中点作为顶点,并且在这个点绘制两次。
(M250,100L250,100L400,400L100,400z)
to_triangle.xml:


<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:interpolator="@android:interpolator/decelerate_cubic"
    android:repeatMode="reverse"
    android:repeatCount="1"
    android:propertyName="pathData"
    android:valueType="pathType"
    android:valueFrom="M100,100L400,100L400,400L100,400z"
    android:valueTo="M250,100L250,100L400,400L100,400z" />

pathInterpolator路径差值器:

<pathInterpolator
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:pathData="M 0.0,0.0 c 0.33333333,0.0 0.0,1.0 1.0,1.0" /> 

*android studio也提供了丰富的图片资源,可以右键module,new->vector Asset选
最后我在网上找的一个开源的Vector的动画Demo库https://github.com/xuyisheng/VectorDemo 有兴趣的可以下载下来研究一下

你可能感兴趣的:(Android进阶之路)