之前對矢量圖形有所耳聞妄痪,但因?yàn)锳ndroid對于矢量圖形的原生支持較晚娄猫,所以一直沒好好研究過(16年2月25就出來的東西昏鹃,其實(shí)就是懶 =寡壮。=)贩疙。最近工作上正好遇到一個產(chǎn)品需求,想用SVG來解決况既,借此機(jī)會對SVG及Android對于矢量圖形的支持做了次了解这溅,當(dāng)然最后依然被SVG坑到,變成手寫XML來解決需求棒仍,不過這都是題外話了悲靴。
SVG是什么?
Scalable Vector Graphics(可縮放矢量圖形)是基于XML莫其,用于描述二維矢量圖形的圖形格式癞尚。SVG由W3C制定耸三,是一個開放標(biāo)準(zhǔn)。SVG本身允許包含3種圖形對象類型:
- 矢量圖形浇揩,包括矩形仪壮、圓、橢圓胳徽、多邊形积锅、直線、任意曲線等养盗。
- 嵌入外部圖像缚陷,包括png、jpeg往核、svg等箫爷。
- 文本。
[from wikipedia]
以下是一個簡單的SVG格式示例:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" />
<path d="M150 0 L75 200 L225 200 Z" />
</svg>
SVG是通過標(biāo)簽的形式來描述圖形,比如<rect>
矩形铆铆、<circle>
圓形蝶缀、<polygon>
多邊形等等普通標(biāo)簽,以及支持復(fù)雜的路徑的標(biāo)簽<path>
.其中Path標(biāo)簽可以通俗的理解為是用命令的方式來控制畫筆薄货,比如:
** 將畫筆移動到指定坐標(biāo)位置 -> 畫一條直線到指定坐標(biāo)位置 -> 再畫一條曲線 -> 完成后抬起畫筆結(jié)束**
當(dāng)然Path標(biāo)簽也需要對應(yīng)的指令來完成操作,比如:
M150 0 L75 200 L225 200 Z
下面是Path支持的對應(yīng)指令:
M = moveto(M X,Y) :將畫筆移動到指定的坐標(biāo)位置
L = lineto(L X,Y) :畫直線到指定的坐標(biāo)位置
H = horizontal lineto(H X):畫水平線到指定的X坐標(biāo)位置
V = vertical lineto(V Y):畫垂直線到指定的Y坐標(biāo)位置
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():關(guān)閉路徑
注意:以上所有命令均允許小寫字母翁都。大寫表示絕對定位,小寫表示相對定位谅猾。
當(dāng)然柄慰,以上只是SVG中很小的一部分,還有其他很多強(qiáng)大的功能税娜。SVG本身已經(jīng)被廣泛使用坐搔,SVG矢量圖與位圖的差別,在于矢量圖可以盡可能的放大而不失真敬矩,并且同一張圖像概行,SVG的實(shí)現(xiàn)可能比png小很多。如果在精簡安裝包的時候弧岳,可以考慮部分圖標(biāo)改成矢量圖的方式凳忙。
Android中的矢量圖替身Vector
Android中對于矢量圖形的處理,并沒有選擇直接支持SVG文件禽炬,所以云端返回的svg格式圖片是無法直接被顯示的涧卵。
不過在Android 5.0中提出了矢量圖片的支持,叫做Vector腹尖。通過創(chuàng)建<vector>標(biāo)簽的xml元素來完成對矢量圖形的定義柳恐。
<!-- res/drawable/heart.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
<!-- intrinsic size of the drawable -->
android:height="256dp"
android:width="256dp"
<!-- size of the virtual canvas -->
android:viewportWidth="32"
android:viewportHeight="32">
<!-- draw a path -->
<path android:fillColor="#8fff"
android:pathData="M20.5,9.5
c-1.955,0,-3.83,1.268,-4.5,3
c-0.67,-1.732,-2.547,-3,-4.5,-3
C8.957,9.5,7,11.432,7,14
c0,3.53,3.793,6.257,9,11.5
c5.207,-5.242,9,-7.97,9,-11.5
C25,11.432,23.043,9.5,20.5,9.5z" />
</vector>
Android Studio從1.4版本開始,包含了一個Vector Asset Studio的工具,可以選擇導(dǎo)入SVG或者PSD文件來幫助我們生成對應(yīng)的vector xml文件。
工具本身支持大多數(shù)主體元素乐设,但并不包含所有的SVG或PSD特性讼庇。SVG導(dǎo)入后的vector xml格式主體參考的是SVG中的pathdata語法,但虛線等屬性伤提、科學(xué)計數(shù)法巫俺、圖案填充(pattern)认烁、漸變(gradient)等特定標(biāo)簽是不支持的肿男。當(dāng)然Vector Asset Studio在我們導(dǎo)入的時候會有明確的提示哪些是被支持的、哪些是不被支持的却嗡。
以下兩種方法都可以打開Vector Asset Studio:
1. 對應(yīng)的drawable目錄上右鍵 -> New -> Vector Asset
2. File -> New -> Vector Asset
Android項目中如何使用Vector?
從Android 5.0開始舶沛,系統(tǒng)提供了兩個Api來完成對Vector的支持:
- VectorDrawable
- AnimatedVectorDrawable
VectorDrawable負(fù)責(zé)矢量圖形的顯示,而AnimatedVectorDrawable負(fù)責(zé)基于矢量圖形的動畫效果窗价。
與此同時如庭,Android Support Library 23.2.0及之后的版本中,也加入了對Vector的向下兼容撼港,引入了VectorDrawableCompat和AnimatedVectorDrawableCompat坪它。
只需要引入對應(yīng)的AppCompat庫
compile 'com.android.support:appcompat-v7:23.2.0'
VectorDrawable API 7+
AnimatedVectorDrawable API 11+
另外需要在 build.gradle 文件中新增如下配置:
//For Gradle Plugin 2.0+
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
//For Gradle Plugin 1.5 or below
android {
defaultConfig {
// Stops the Gradle plugin’s automatic rasterization of vectors
generatedDensities = []
}
// Flag notifies aapt to keep the attribute IDs around
aaptOptions {
additionalParameters "--no-version-vectors"
}
}
如何使用VectorDrawable?
在布局文件中,我們可以針對ImageVIew帝牡、ImageButton等控制設(shè)置對應(yīng)的矢量圖片往毡。
如果用的Support包,那只需要通過app:srcCompat=“”
屬性來替代以前的android:src
即可靶溜。
另外記得添加xmlns:app="http://schemas.android.com/apk/res-auto"
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_build_black_24dp"
tools:layout_editor_absoluteX="11dp"
tools:layout_editor_absoluteY="225dp"
android:id="@+id/imageButton"
android:tint="@color/colorAccent" />
如果使用的是Andorid5.0以上的原生支持开瞭,可以直接使用android:src=“”
來完成對應(yīng)的展現(xiàn)。
如何使用AnimatedVectorDrawable罩息?
AnimatedVectorDrawable其實(shí)是針對Vector里面的各種元素嗤详,提供了屬性動畫的支持方式,從而完成對應(yīng)的動畫效果瓷炮。
借用官方文檔里的例子葱色,如果采用多個xml來實(shí)現(xiàn):
VectorDrawable's XML file: vd.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="64dp"
android:width="64dp"
android:viewportHeight="600"
android:viewportWidth="600" >
<group
android:name="rotationGroup"
android:pivotX="300.0"
android:pivotY="300.0"
android:rotation="45.0" >
<path
android:name="vectorPath"
android:fillColor="#000000"
android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
</group>
</vector>
AnimatedVectorDrawable's XML file: avd.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/vd" >
<target
android:name="rotationGroup"
android:animation="@anim/rotation" />
</animated-vector>
Animator XML file that is used in the AnimatedVectorDrawable's XML file: rotation.xml
<objectAnimator
android:duration="6000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360" />
最后在布局中的使用方法,跟使用VectorDrawable是一樣的:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/avd"/>
</android.support.constraint.ConstraintLayout>
當(dāng)然到此為止還有最重要的一步娘香,否則看到的還只是靜態(tài)的矢量圖形:
ImageView demoView = (ImageView) findViewById(R.id.imageview);
if(demoView.getDrawable() instanceof Animatable){
((Animatable) demoView.getDrawable()).start();
}
上面是多xml的例子苍狰,相當(dāng)于矢量圖形、動畫目標(biāo)茅主、動畫規(guī)則是分開的舞痰。還有一種方式是用單一的xml文件來描述整個矢量動畫資源,需要Build Tools 版本在24及以上:
<?xml version="1.0" encoding="utf-8"?>
<animated-vector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt">
<aapt:attr name="android:drawable">
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportWidth="600"
android:viewportHeight="600">
<group
android:name="rotationGroup"
android:pivotX="300"
android:pivotY="300"
android:rotation="45.0" >
<path
android:name="vectorPath"
android:fillColor="#000000"
android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
</group>
</vector>
</aapt:attr>
<target android:name="rotationGroup">
<aapt:attr name="android:animation">
<objectAnimator
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360"
android:duration="6000"
/>
</aapt:attr>
</target>
</animated-vector>
因?yàn)锳nimatedVectorDrawable改變的是vector中各元素的屬性值诀姚,所以極大的增添了動畫的實(shí)現(xiàn)手段及效果响牛。
不過坑依然有,當(dāng)API < 21時,擴(kuò)展包中的AnimatedVectorDrawableCompat會有一些限制:
Path Morphing (PathType evaluator) Used to morph one path into another path.
Path Interpolation Used to define a flexible interpolator (represented as a path) instead of the system-defined interpolators like LinearInterpolator.
Move along path The geometry object can move around, along an arbitrary path, as part of an animation.
在此限制下呀打,最能發(fā)揮效果的pathdata路徑動畫基本就可以忽略了矢赁。至少在發(fā)此文章的時候以上限制還在,只能默默期待以后吧贬丛。
總結(jié)
此文只是初略的講述了Android中矢量圖形的基礎(chǔ)使用方法撩银,當(dāng)然深入來講其實(shí)還有很多東西,包括第三方的一些SVG庫豺憔、矢量動畫的一些高級用法等等额获。在此只是做一個用法的基本記錄,同時希望也是借此機(jī)會拋磚引玉恭应,給大家提供一個新的處理思路吧抄邀。