VectorDrawable简单介绍

2018-10-28 10:50:26

摘要

从5.0(API等级21)开始,android开始支持矢量图了。关于什么是矢量图以及矢量图有什么优缺点不在本文的涉及范围之内,具体可以参考矢量图百科。不过这里要提一下它的优点:

  • 保存最少的信息,文件大小比位图要小,并且文件大小与物体的大小无关

  • 任意放大矢量图形,不会丢失细节或影响清晰度,因为矢量图形是与分辨率无关的。

从以上两个优点来看,在项目中使用矢量图至少可以缩小我们apk包的尺寸,而且可以在屏幕适配时提供很大的方便,因为矢量图是分辨率无关的。

前面也说了,矢量图从21才开始支持。那么如果我想往下兼容改怎么办呢?这个问题要放在以前的话,我会说github下就有你要的答案。但现在我不会这么说,因为前段时间Google升级了support library,官方向后兼容了矢量图的使用。要问兼容到哪个版本,我告诉你矢量图兼容到API7,矢量图动画兼容到API11(是不是已经满足了你的使用)。

好了,下面我们就来说说怎么在项目中使用矢量图。

VectorDrawable的使用

按照官方的说法,要在低版本上使用矢量图,需要在项目中引入新的兼容库support-vector-drawable,并且appcompat-v7库的版本要在23.2.0+(写文章这会23.2.1已经发布了)。而且你还要修改下gradle的相关配置,不要让gradle在构建的时候为你在低版本(API21以下)的情况下生成针对于不同密度的png文件,因为android studio1.4的时候支持了矢量图。

修改appcompat-v7的版本
compile 'com.android.support:appcompat-v7:23.2.0'

NOTE: 这里我只引入了23.2.0版本的appcompat-v7库,同步gradle后就编译出了support-vector-drawable-23.2.0和animated-vector-drawable-23.2.0这两个库。

修改gradle配置文件

如果你的gradle插件的版本为2.0以下,你应该这么修改

android {
  defaultConfig {    // 不让gradle自动生成不同屏幕分辨率的png图
    generatedDensities = []
  }
  
  aaptOptions {
    additionalParameters "--no-version-vectors"
  }
}

如果你的gradle插件版本是2.0+,你 应该这么修改

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

经过上面这几步的修改,你就可以在项目中使用矢量图了。那么,下面我们就正式来说说怎么使用。

android studio为我们提供了一个Vector Asset Studio的工具,让我么可以从material icon和svg文件生成矢量图。具体用法可以参考官方的说明文档,这里就不多说了。

Android中矢量图是以xml文档的形式存在的,像下面这样就定义了一个矢量图,里面包含了关于该矢量图的数据信息。

<!-- res/drawable/heart.xml --><vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportHeight="24.0"
    android:viewportWidth="24.0">
    <path
        android:fillColor="#FF000000"
        android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM15.5,11c0.83,0 1.5,-0.67 1.5,-1.5S16.33,8 15.5,8 14,8.67 14,9.5s0.67,1.5 1.5,1.5zM8.5,11c0.83,0 1.5,-0.67 1.5,-1.5S9.33,8 8.5,8 7,8.67 7,9.5 7.67,11 8.5,11zM12,17.5c2.33,0 4.31,-1.46 5.11,-3.5L6.89,14c0.8,2.04 2.78,3.5 5.11,3.5z" /></vector>

这是我通过material icon生成的,它在android中对应着VectorDrawable这个类,也就是兼容包中的VectorDrawableCompat这个类。

定义好矢量图形后,我们就可以向普通的图形那样来使用它了。不过有几点需要注意:

  • 使用android:src属性的地方需要替换为app:srcCompat属性

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.damon.vectordrawabledemo.MainActivity">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:srcCompat="@drawable/ic_mood_black_24dp" /></RelativeLayout>
  • 在非src属性的地方使用矢量图时,需要将矢量图用drawable容器(如StateListDrawable, InsetDrawable, LayerDrawable, LevelListDrawable, 和RotateDrawable)包裹起来使用。否则会在低版本的情况下报错。

而在代码中的使用和普通的png图没什么区别,调用的是同样的API。

这样我们就把矢量图引入到我们的项目中了,下面我贴几张图来对比下矢量图和png图的不同,以此来展示下矢量图的优点。

首先是png的原图和放大图


其次是矢量图的原图和放大图


对比一目了然。而且矢量图的xml的大小只有655个字节,而不同分辨率的png的大小加起来有好几k。矢量图只需要维护一个xml,而png需要维护多个图形资源。

矢量图xml文件支持的标签以及属性可以参考这里,包括了常见的填充、描边、着色等。

使用矢量图制作动画

23.2的支持库同样也放出了矢量图动画对应的兼容版本AnimatedVectorDrawableCompat,对应的兼容包是animated-vector-drawable,xml标签则是animated-vector。AnimatedVectorDrawableCompat能够以属性动画的形式来驱动VectorDrawable实现动画,具体来说需要分三步走:

  • 定义一个VectorDrawableCompat的xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    <!-- 图片本身的大小 -->
    android:width="500px"
    android:height="500px"
    <!-- 画布的大小 -->
    android:viewportHeight="500"
    android:viewportWidth="500">    <!-- 用来把多个path或者subgroup组合起来,group提供了一些属性比如旋转、缩放、平移。这些属性值得变化会反应在它内部的path和subgroup元素上-->
    <group
        android:scaleX="5.0"
        android:scaleY="5.0">
        <!-- 这里group和path有一个name属性,这个属性用来在使用动画时指定动画要驱动的对象 -->
        <path
            android:name="star"
            android:pathData="M 50.0,90.0 L 82.9193546357,27.2774101308 L 12.5993502926,35.8158045183 L 59.5726265715,88.837672697 L 76.5249063296,20.0595700732 L 10.2916450361,45.1785327898 L 68.5889268818,85.4182410261 L 68.5889268818,14.5817589739 L 10.2916450361,54.8214672102 L 76.5249063296,79.9404299268 L 59.5726265715,11.162327303 L 12.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 L 23.4750936704,79.9404299268 L 89.7083549639,54.8214672102 L 31.4110731182,14.5817589739 L 31.4110731182,85.4182410261 L 89.7083549639,45.1785327898 L 23.4750936704,20.0595700732 L 40.4273734285,88.837672697 L 87.4006497074,35.8158045183 L 17.0806453643,27.2774101308 L 50.0,90.0Z"
            android:strokeColor="@color/colorAccent"
            android:strokeWidth="2" />
    </group></vector>
  • 定义AnimatedVectorDrawableCompat的xml

<?xml version="1.0" encoding="utf-8"?><animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/vector_drawable">
    <target
        android:name="star"
        android:animation="@animator/star_anim" /></animated-vector>

可以看到,根元素是animated-vector,并且有一个必须的属性android:drawable用来指定要驱动的矢量图对象。子标签target一方面用来指定要驱动的矢量图内的group和path的名称(这里和VectorDrawableCompat的xml中的group和path名称对应);另一方面指定要使用哪个属性动画来驱动group和path的属性进行变化来产生动画效果。

  • 创建属性动画

驱动trimPathStart和strokeColor属性的动画

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" >
    <objectAnimator
        android:duration="5000"
        android:propertyName="trimPathStart"
        android:repeatCount="infinite"
        android:repeatMode="restart"
        android:valueFrom="1"
        android:valueTo="0" />
    <objectAnimator
        android:duration="5000"
        android:propertyName="strokeColor"
        android:repeatCount="infinite"
        android:repeatMode="restart"
        android:valueFrom="@color/colorAccent"
        android:valueTo="@color/colorPrimaryDark" /></set>

这样,准备工作就做好了。我们就可以使用矢量图动画了。把ImageView的src更改为矢量图动画

<ImageView
       android:id="@+id/image_view"
       android:layout_width="200dp"
       android:layout_height="200dp"
       app:srcCompat="@drawable/vector_drawable_anim" />

在Java代码中启动动画

ImageView imageView = (ImageView) findViewById(R.id.image_view);
Drawable drawable = imageView.getDrawable();//AnimatedVectorDrawableCompat实现了Animatable接口if (drawable instanceof Animatable){
   ((Animatable) drawable).start();
}

这样就实现了矢量图动画,看看效果图吧。

好了,关于矢量图以及矢量图动画的使用就说这么多。具体的一些细节以及xml中的其他属性啥的怎么使用可以参考官方文档,自己亲自试一试就会很明了了。源码在这里,欢迎star and fork。



作者:DamonZh
链接:https://www.jianshu.com/p/456df1434739
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  • 2020-03-19 19:15:47

    vue中methods watch和compute的区别和联系

    首先要说,methods,watch和computed都是以函数为基础的,但各自却都不同 而从作用机制和性质上看,methods和watch/computed不太一样,所以我接下来的介绍主要有两个对比: 1.methods和(watch/computed)的对比

  • 2020-03-19 19:50:31

    用vue做的跟随鼠标移动的div

    随鼠标移动的动画效果,之前一直使用angular和react,没怎么接触过vue,先做一个vue的简单例子,然后再整合。

  • 2020-03-20 13:35:55

    随便想到,群聊天的数据库简单设计

    拆分成两个表,一个是消息的流水表,一个是每个人的配置表。 记录每个群下面的这个用户的最后读取的消息last_msg_id,然后在计算消息未读数据。 这样优化之后数据将减少好多,数量是 m+n条数据。不在是成倍增长了。

  • 2020-03-20 13:39:50

    类似与微信朋友圈功能数据库如何实现

    每次发圈子的时候,给关注我的每个uuid,发一个内容id。 大概表的设计就是 uuid,idlist 这样的,idlist是按照时间顺序的。 然后定期删除idlist过多的老圈子。

  • 2020-03-21 00:11:38

    Android卡片布局(圆角阴影)的几种实现及分析

    在开发中,为了界面美观,圆角view和阴影效果是开发中经常遇到的UI场景,比如银行卡效果,卡片式itemView布局,Banner图等,开发中我们通过各种方式实现了这种效果,但是哪种方案最好呢,接下来本文将比较几种常见的圆角阴影布局实现,并从内存占用角度分析它们的优缺点.

  • 2020-03-21 12:05:24

    android 自定义组件,使用AttributeSet

    首先要在res/values目录下建立一个attrs.xml(名字可以自己定义)的文件,并在此文件中增加对控件的属性的定义.其xml文件如下所示:

  • 2020-03-21 12:09:59

    Android使用AttributeSet自定义控件的方法

    我们可以在attrs.xml中声明自己控件的属性,在布局xml文档中声明自己的命名空间,这时就可以对设置自己想要的值了,然后在AttributeSet这个属性中获取对应的值。好了不多说,我们来看下代码,一切尽在不言中:

  • 2020-03-22 21:16:07

    用vue做的跟随鼠标移动的div

    最近接到一个任务,就是在既存用electron-vue开发的桌面端程序上追加随鼠标移动的动画效果,之前一直使用angular和react,没怎么接触过vue,先做一个vue的简单例子,然后再整合。