android中利用矢量图VectorDrawable打造酷炫动画

来源:互联网 发布:滨州行知中学暴力事件 编辑:程序博客网 时间:2024/05/18 12:38

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 xmlns:android="http://schemas.android.com/apk/res/android"        android:width="24dp"        android:height="24dp"        android:viewportWidth=“500.0"        android:viewportHeight=“500.0">    <path        android:fillColor="#FF000000"        android:pathData=“M100,100 L400,100 L100,400 Z"/></vector>

  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.xml的VectorDrawable图像,要把他使用在ImageView中来,我们引入代码如下:
<ImageView    android:layout_width="100dp"    android:layout_height="100dp"    app:srcCompat="@drawable/ic_face_black_24dp”/>
这样,我们就可以在ImageView中显示一个静态的VectorDrawable,ImageView的宽高指定任意值,Vector图片都不会失真。这里有个地方需要注意,我们的Activity需要继承AppCompatActivity才可以正常显示VectorDrawable。

Button中,我们通过app:srcCompat设置Vector图片作为背景时,会发现不起作用,Google的解释是像Button这样带有状态的控件,我们不可以直接使用app:srcCompat来设置背景图片,但是,可以通过selector来设置不同点击态的背景
如我们创建了一个bt_bg_vector.xml的selector:
<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android">    <item android:drawable="@drawable/ic_face_black_24dp" android:state_pressed="true"/>    <item android:drawable="@drawable/ic_assignment_ind_black_24dp"/></selector>
此时,我们在Button中引用bt_bg_vector.xml作为点击态的背景,代码如下:

<Button    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:background="@drawable/bt_bg_vector" />
如此,我们就可以方便的在ImageView、ImageButton、Button中设置静态的VectorDrawable,是不是跟png图片使用差别不大。

3.2 动态的VectorDrawable

前面我们看到了VectorDrawable的一些优势,比如:体积小、支持任意放大缩小等,但这并不足以让开发者放弃位图而转向VectorDrawable,下面我们来看一下VectorDrawable又一个惊天大优势,可以方便的使用动画。

VectorDrawable中要使用属性动画,我们需要使用animated-vector,animated-vector其实也是一个XML文件,我们可以理解为配置动画的粘合剂,animated-vector将我们的目标VectorDrawable图像和所需要的属性动画animator进行了连接。
animated-vector代码如下所示:
<?xml version="1.0" encoding="utf-8"?><animated-vector xmlns:android="http://schemas.android.com/apk/res/android"    android:drawable="@drawable/ic_thumbs_up_down_black_24dp">    <target        android:name="arrow_left"        android:animation="@animator/anim_left" />    <target        android:name="arrow_right"        android:animation="@animator/anim_right" />    </animated-vector>
其中android:drawableVectorDrawable图片名称android:name是对应VectorDrawable中group的name(group后面再介绍),android:animation是要移动的属性动画,animated-vector标签在现在的Android Studio中实际上是会报错的,但这个并不影响编译和运行,属于Android Studio的Bug。
ic_thumbs_up_down_black_24dp代码如下:
<vector xmlns:android="http://schemas.android.com/apk/res/android"    android:width="24dp"    android:height="24dp"    android:viewportHeight="24.0"    android:viewportWidth="24.0">    <group        android:name="arrow_left">        <path            android:fillColor="#FF559955"            android:pathData="M12,6c0,-0.55 -0.45,-1 -1,-1L5.82,5l0.66,-3.18 0.02,-0.23c0,-0.31 -0.13,-0.59 -0.33,-0.8L5.38,0 0.44,4.94C0.17,5.21 0,5.59 0,6v6.5c0,0.83 0.67,1.5 1.5,1.5h6.75c0.62,0 1.15,-0.38 1.38,-0.91l2.26,-5.29c0.07,-0.17 0.11,-0.36 0.11,-0.55L12,6z" />    </group>    <group        android:name="arrow_right">        <path            android:fillColor="#FFaa3333"            android:pathData="M22.5,10h-6.75c-0.62,0 -1.15,0.38 -1.38,0.91l-2.26,5.29c-0.07,0.17 -0.11,0.36 -0.11,0.55L12,18c0,0.55 0.45,1 1,1h5.18l-0.66,3.18 -0.02,0.24c0,0.31 0.13,0.59 0.33,0.8l0.79,0.78 4.94,-4.94c0.27,-0.27 0.44,-0.65 0.44,-1.06v-6.5c0,-0.83 -0.67,-1.5 -1.5,-1.5z" />    </group></vector>
因为属性动画要改变绘制的图片属性来实现动画,可是path标签中并没有这种属性,因此,VectorDrawable要想使用属性动画,就需要用group标签来封装path标签,将属性动画作用在group标签中,这里使用group标签将vector图片分成了两组,如果图片比较复杂,会将其分成多组。
上面准备工作做好后,就可以在我们代码中直接使用了,使用也和普通Vector图片一样,如下:
<ImageView    android:id="@+id/arrow"    android:layout_width="100dp"    android:layout_height="100dp"    app:srcCompat="@drawable/arrow_anim" />
这样,我们在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如下:
<vector xmlns:android="http://schemas.android.com/apk/res/android"    android:width="150dp"    android:height="24dp"    android:viewportHeight="24"    android:viewportWidth="150">    <path        android:name="search"        android:pathData="M141,17 A9,9 0 1,1 142,16 L149,23"        android:strokeAlpha="0.8"        android:strokeColor="#000000"        android:strokeLineCap="round"        android:strokeWidth="2"/>    <path        android:name="bar"        android:pathData="M0,23 L149,23"        android:strokeAlpha="0.8"        android:strokeColor="#000000"        android:strokeLineCap="square"        android:strokeWidth="2"/></vector>

这其实就是我们android应用中常见的搜索框,我们将这个Vector分为两个path,一个path就是一个放大镜的图标,另外一个就是一条直线,那么我们现在需要给这个searchbar一个动画效果,但我们并不需要对图片进行平移、缩放或变色这种基本的动画,我们需要改变这个图片的路径,VectorDrawable给我们提供了这种比较绚丽的动画效果,那就是trimPathStart属性。trimPathStart属性可以模拟Vector图片的路径生成,就像人拿了一个画笔,一点一点绘制出我们这个图片一样。trimPathStart的使用和属性动画其它属性的使用相同,属性动画文件如下anim_bar.xml:

<?xml version="1.0" encoding="utf-8"?><objectAnimator    xmlns:androd="http://schemas.android.com/apk/res/android"    androd:duration="1500"    androd:propertyName="trimPathStart"    androd:repeatCount="infinite"    androd:repeatMode="reverse"    androd:valueFrom="0"    androd:valueTo="1"    androd:valueType="floatType"></objectAnimator>

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:
<?xml version="1.0" encoding="utf-8"?><animated-vector    xmlns:android="http://schemas.android.com/apk/res/android"    android:drawable="@drawable/searchbar">    <target        android:animation="@animator/anim_search"        android:name="search"/>    <target        android:animation="@animator/anim_bar"        android:name="bar"/></animated-vector>
这样,我们就可以在Image中直接使用searchbar_anim,来实现我们的搜索动画了。
<ImageView    android:id="@+id/search_bar"    android:layout_width="200dp"    android:layout_height="50dp"    app:srcCompat="@drawable/searchbar_anim" />
在activity中使用如下代码开始动画:
if(searchBar.getDrawable() instanceof Animatable){    ((Animatable)searchBar.getDrawable()).start();}

学好VectorDrawable,我们可以很方便的实现许多较复杂的动画效果,今天就先介绍这么多了。。。。
项目gitHub地址:https://github.com/gjnm/AndroidDraw




阅读全文
0 0
原创粉丝点击