矢量图SVG
从Android 5.0开始,Android允许开发者使用SVG图片作为图片资源,有关SVG的更多信息可以查看w3school上面的相关介绍。
矢量图有什么优点呢?首先,矢量图不会失真,不管放大多少倍,矢量图都是无损的,其次,矢量图的大小往往是jpg图片的十几分之一,很适合作为程序中使用,而且结合Android退出的矢量图动画,更能做出一些很炫酷的动效,下面我就来介绍下,如何在Android中使用矢量图。
获取一张矢量图并导入
首先想要获取矢量图资源,强烈推荐阿里巴巴图标库,其次,Android Studio也自带了全套的Material Design图标,很是nice。导入方式也很简单,首先在res文件夹上面右键,如下图所示就可以导入SVG图片了,可以选择Material Design中的矢量图或者导入我们自己下载的矢量图。
导入以后的矢量图在drawable文件夹下面,具体是如下形式,显示出来是一个向左的箭头,关键的是(整个文件只有352B不到1KB!!!!)
<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:fillColor="#FF000000" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/> </vector>
vector标签介绍
其中android:width以及android:height不用多说,说的是图片的大小,重点是android:viewportWidth以及android:viewportHeight,这两个属性代表的含义是将前面定义的宽高等分为多少份,上面的例子中就是将24dp分成24份,这样就有了一个24x24的坐标系,然后path代表的是线,android:pathData就是这条线中一些点的坐标,具体可以查看SVG语法。
通过上面的分析,我们可以知道,其实vector类似于描述了一个坐标系,然后通过path等设置一系列的点、线在坐标系中绘制图形,这也是为什么SVG图片不失真的原因。至于上面定义的 android:width="24dp"与android:height="24dp",我们在使用的时候,可以设置控件的宽高,让其被拉伸,毕竟不会失真。
SVG图片的兼容之路
最前面也说了,SVG图像是Android 5.0以后引入的,在5.0之前使用矢量图会怎么样呢?经过我的实验是,啥事都木有,正常显示,先放下手里的板砖听我解释,其实看看下面这张图就知道了。可以看到,在drawable-anydpi-v21文件夹里面的是矢量图,其他几个png图片是Android Studio自动帮我们生成的,当设备版本大于5.0的时候,使用矢量图,5.0以下的时候,会使用png图片。
不过上面也提到了,我们使用矢量图的一个重大原因是矢量图比较小巧,别看上图中显示的是1.99kb,那是被自动对齐以后的,如果编译器帮我们生成了png,那不是与我们的初衷相悖么。
关于这一点,可以参看官方文档。 如果只想使用SVG图片,那么需要修改 build.gradle 文件以及使用com.android.support:appcompat-v7:23.2.0 +
// Gradle Plugin 2.0+ android { defaultConfig { vectorDrawables.useSupportLibrary = true //指定生成哪种分辨率下的位图资源 vectorDrawables.generatedDensities = ['hdpi','xxhdpi'] } } //或更高 dependencies { compile 'com.android.support:appcompat-v7:23.2.0' }
如果使用Gradle版本较低
// Gradle Plugin 1.5 android { defaultConfig { generatedDensities = [] } // This is handled for you by the 2.0+ Gradle Plugin aaptOptions { additionalParameters "--no-version-vectors" } } //或更高 dependencies { compile 'com.android.support:appcompat-v7:23.2.0' }
在布局文件中使用
<ImageView xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/main_svg_img" android:layout_width="50dp" android:layout_height="50dp" app:srcCompat="@drawable/ic_transfer_within_a_station_black_24dp"/>
可以看到,我这里使用的是app:srcCompat,并且使用此View的Activity必须继承AppCompatActivity,如果不使用app:srcCompat会直接崩溃,如果不继承AppCompatActivity,那么图片就没了,程序运行时改变可以直接调用mSvgImg.setImageResource方法。可参见官方文档。
其他控件
对于Button来说,使用 app:srcCompat 没有啥效果,不过我们可以取巧,为Button设置一个android:background为selector,然后在selector中使用SVG图像即可,不过,会崩溃!!!
解决方法,在Activity中加入如下代码
static { AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); }
不过设置的selector无效,只能显示selector中默认的那个SVG图片。参考链接:http://www.jianshu.com/p/e3614e7abc03
SVG图片动画
终于到了激动人心的动画时刻了,其实对于Android目前来说,一般使用SVG图片用来进行一些nice的动画效果,如下图。使用传统动画都无法实现这种效果。
首先要使用SVG图片动画,其实与我们上面使用SVG图片类似,首先需要一个SVG图片,上图中的图片为。
<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>
上面name为search的代表那个搜索图标,下面name为bar的代表下划线,之所以这里添加了name属性,是为了让我们在进行动画的时候,能控制指定部分的图像。
有了SVG图片,那么我们还需要使用animated-vector标签来将动画与SVG图像联系在一起。如下
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/searchbar"> <target android:name="search" android:animation="@animator/anim_searchbar_in"/> <target android:name="bar" android:animation="@animator/anim_searchbar_out"/> </animated-vector>
可以看到animated-vector中的android:drawable="@drawable/searchbar"代表需要执行动画的SVG图片,里面的target标签一看就懂,name就是我们在上面指定的name,android:animation就是代表在指定的name上面需要进行的动画。
好了,接下来我们指定动画就可以了,可是我们使用什么区指定动画呢?答案就是属性动画。因为SVG标签path、grou、vector、clip-path都有自己的属性,所以我们可以使用属性动画动态设置其属性,这样就完成动画了。下面贴出其有效属性。
标签 | 属性名 | 含义 | 取值范围 | 类型 |
<vector> | alpha | 透明度 | 0-1 | floatType |
<group> | rotation | 旋转角度 | 0-360 | floatType |
pivotX | 旋转中心X | ? | floatType | |
pivotY | 旋转中心Y | ? | floatType | |
scaleX | X轴缩放 | ? | floatType | |
scaleY | Y轴缩放 | ? | floatType | |
translateX | X轴平移 | ? | floatType | |
translateY | Y轴平移 | ? | floatType | |
<path> | pathData | ? | ? | ? |
fillColor | 填充色 | ? | colorType | |
strokeColor | 描边色 | ? | colorType | |
strokeWidth | 描边宽 | ? | ? | |
strokeAlpha | 描边透明度 | ? | ? | |
fillAlpha | 填充透明度 | 0-1 | floatType | |
trimPathStart | 路径开始到结束 | 0-1 | floatType | |
trimPathOffset | ? | ? | ? | |
<clip-path> | pathData | ? | ? | ? |
?号表示不确定或者未实验,官方文档:https://developer.android.com/reference/android/graphics/drawable/AnimatedVectorDrawable.html?hl=zh-cn
下面贴出anim_searchbar_out.xml,其他的可查看文末源码地址。
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="1000" android:propertyName="trimPathStart" android:repeatCount="infinite" android:repeatMode="reverse" android:valueFrom="1" android:valueTo="0" android:valueType="floatType"/>
可以看到,设置trimPathStart从1-0,表示先从全部显示慢慢"缩到"没有,然后无限循环,不停倒放,个人实验发现android:valueType不是必须写明的。
然后通过app:srcCompat将animated-vector设置给ImageView即可。
最后启动动画代码
ImageView imageView = (ImageView) view; Drawable drawable = imageView.getDrawable(); //开始动画,此方法兼容5.0之前 if (drawable instanceof Animatable) { ((Animatable) drawable).start(); }
至此,我们已经能够在Android 2.1以上版本上面使用SVG图片了,并且也能使用SVG动画了。
源码地址:https://github.com/CB2Git/BlogDemoRepository/tree/master/VectorDemo