一、Vector
優點
VectorDrawable
主要有兩個優點:螢幕自適應和體積小。
- 如果我們使用的是普通的
png
或者jpg
圖片,那麼為了能讓圖片在不同解析度的機型上能夠很好地展現,通常會在各個drawable
資料夾下放置不同解析度大小的圖片檔案,而VectorDrawable
則不需要,僅僅只使用一套資源,就能夠適應任何解析度的手機。 - 對於某些圖片,
VectorDrawable
素材的大小要比png
和jpg
小很多。
二、SVG
和Vector
的基本概念
下面,我們先介紹一下SVG
和VectorDrawable
的基本概念:
SVG
:它並不是Android
平臺特有的概念,它的全稱為可縮放向量圖形,簡單的來說,就是用於描述二維向量圖形的圖形格式,更加詳細的解釋可以參考:SVG - 百度百科。VectorDrawable
:它是Android
當中的SVG
實現,它並不支援SVG
的全部語法,只是支援部分有必要的部分。
三、獲取VectorDrawable
俗話說的好,巧婦難為無米炊,這一節我們就來介紹一下如何獲得一個VectorDrawable
,一般獲取的方式有以下三種方式:
- 先獲取
SVG
素材,再通過工具轉換成為VectorDrawable
- 通過
Android Studio
中的素材庫,直接獲取VectorDrawable
- 根據
Vector
的語法,自己描述
3.1 先獲取SVG
素材,再通過工具轉換成為VectorDrawable
首先獲取SVG
素材,再將它轉換成為VectorDrawable
是最常用的方式,而SVG
素材的獲取又有以下幾種途徑:
- 網站直接下載
SVG
影象 - 由
UI
設計師使用專業的工具匯出 - 通過 VectorMagic 軟體,將
png
和jpg
素材轉換為SVG
影象
對於個人開發者而言,一般都會採用第一種方式,我們這裡也只介紹第一種方式。很多文章都推薦過這個網站:iconFront - 阿里巴巴,它提供了SVG
和PNG
素材的直接下載:
![圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解](https://i.iter01.com/images/ac2f8c543d6a928ac85c9b575b3a9b3b6e3db2c51a115bd85bc3b4458d849abe.png)
Android Studio
的New
選項中,選擇Vector Asset
:
![圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解](https://i.iter01.com/images/386fac8cde2547305e42326998b794e1bec852c84dfaa48d52874964b2bd3520.png)
Local file
,並開啟我們下載後的影象,再選擇next
儲存到指定的資料夾:
![圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解](https://i.iter01.com/images/bca0b16fc4e9048bfcccfa004fe4895e32bb347e83ea97985d93877b6762b59a.png)
*.xml
檔案,這個就是VectorDrawable
:
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:viewportHeight="1024.0"
android:viewportWidth="1024.0"
android:width="24dp">
<path android:fillColor="#FF000000"
android:pathData="M887.9,298.2c-12.9,-12.1 -33.2,-11.5 -45.2,1.4L415.9,754l-233.1,-229.7C170.2,511.9 150,512 137.5,524.6c-12.4,12.6 -12.3,32.9 0.4,45.2l256.5,252.7c0.1,0.1 0.2,0.1 0.3,0.2 0.1,0.1 0.1,0.2 0.2,0.3 2,1.9 4.4,3 6.8,4.3 1.2,0.7 2.1,1.7 3.4,2.1 3.8,1.5 7.8,2.2 11.7,2.2 4.2,0 8.4,-0.8 12.3,-2.5 1.3,-0.5 2.3,-1.7 3.6,-2.4 2.4,-1.4 4.9,-2.6 6.9,-4.7 0.1,-0.1 0.1,-0.3 0.2,-0.4 0.1,-0.1 0.2,-0.1 0.3,-0.2l449.2,-478.2C901.4,330.6 900.8,310.3 887.9,298.2z"/>
</vector>
複製程式碼
3.2 通過Android Studio
中的素材庫,直接獲取VectorDrawable
還是在上面的那個介面,我們勾選另外一個選項:
![圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解](https://i.iter01.com/images/bf4b0edc30ae62eb73673f0c505274e93711391b4ac6beac2fb1f722433807b6.png)
Material Design
提供的素材庫:
![圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解](https://i.iter01.com/images/490737a994c12e1392f00e2d6d8b92f0be4b9d2978219dfc8ea284fa3c11105f.png)
*.xml
的VectorDrawable
:
<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="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,5c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM12,19.2c-2.5,0 -4.71,-1.28 -6,-3.22 0.03,-1.99 4,-3.08 6,-3.08 1.99,0 5.97,1.09 6,3.08 -1.29,1.94 -3.5,3.22 -6,3.22z"/>
</vector>
複製程式碼
3.3 根據Vector
的語法,自己描述
在3.1
和3.2
當中,我們可以看到,最終VectorDrawable
都是用一個*.xml
來表示的,那麼,我們當然可以根據SVG
的語法,來編寫一個xml
檔案,通過pathData
屬性進行描述,不過這種方式較為繁瑣,一般不會採用。
四、Vector
語法
雖然說大多數情況下,我們不會完全手動去編寫Vector
的xml
檔案,但是,對於Vector
的基本語法還是有必要了解一些的,因為在我們後邊談到的動態Vector
中需要了解對於每個標籤有哪些屬性可以設定,Vector
包含下面三種標籤:
<vector>
<group>
<path>
<path>
</group>
</vector>
複製程式碼
4.1 <vector>
標籤
name
:向量圖的名字width, height
:向量圖的固有寬高,通常使用dp
。viewportWidth, viewportHeight
:把向量圖的寬高分成多少個單元,這裡的每個單元就對應pathData
中的一個點座標。
4.2 <path>
標籤
name
:路徑的名稱。fillColor
:圖形的填充顏色。pathData
:定義控制點的位置,類似與Canvas
當中的Path
類。
4.3 <group>
標籤
<group>
用來把多個<path>
組合在一起,進行相同的處理。
更多的屬性可以查閱下面這兩篇文章:
VectorDrawable 詳解 Android 中的 SVG 影象的各個屬性意義
五、Vector
的相容性問題
為了讓VectorDrawable
能夠在Android 5.0
以下版本的手機上使用,我們需要引入support
包,並修改gradle
的配置。
5.1 引入support
包
VectorDrawable
是在Android 5.0
之後提出來的,因此,如果我們需要在低版本上使用,那麼就要引入com.android.support:appcompat-v7
包,要求版本號大於等於23.2.0
,這裡我們選用的是:
compile 'com.android.support:appcompat-v7:25.3.1'
複製程式碼
與Vector
相關的兩個包為:
![圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解](https://i.iter01.com/images/babab5d6a6738c26e16d9038989ef528c590618efa4f064ce6952188d47a406d.png)
5.2 修改gradle
配置檔案
如果**gradle
的版本小於2.0
**:
android {
defaultConfig {
generatedDensities = []
}
aaptOptions {
additionalParameters "--no-version-vectors"
}
}
複製程式碼
如果**gradle
的版本大於2.0
**,例如我們所用的版本:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
}
}
複製程式碼
那麼需要這樣配置:
android {
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
}
複製程式碼
關於更多相容性的問題,可以檢視下面這篇文章
六、靜態VectorDrawable
如果使用靜態的方式展示VectorDrawable
,那麼很簡單,只需要像使用普通的drawable
一樣,首先,我們按照第三節的方法,獲取到一個vectorDrawable
,並把它放在drawable
資料夾下:
<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="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,5c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM12,19.2c-2.5,0 -4.71,-1.28 -6,-3.22 0.03,-1.99 4,-3.08 6,-3.08 1.99,0 5.97,1.09 6,3.08 -1.29,1.94 -3.5,3.22 -6,3.22z"/>
</vector>
複製程式碼
我們可以應用於:
ImageView
的src
View
的background
TextView
的drawable
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal">
<ImageView
android:id="@+id/iv_static"
android:layout_width="50dp"
android:layout_height="50dp"
android:clickable="true"
android:src="@drawable/ic_account_circle_selector"/>
<View
android:layout_width="50dp"
android:layout_height="50dp"
android:clickable="true"
android:background="@drawable/ic_account_circle_selector"/>
<TextView
android:drawableStart="@drawable/ic_account_circle_black_24dp"
android:text="UserName"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
複製程式碼
在上面的例子中,我們還使用了ic_account_circle_selector
,其定義如下:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_account_circle_black_24dp" android:state_pressed="true"/>
<item android:drawable="@drawable/ic_account_circle_black_normal_24dp"/>
</selector>
複製程式碼
ic_account_circle_black_24dp
就是之前獲取到的素材,而ic_account_circle_black_normal_24dp
就是改變了它的fillColor
屬性:
<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="#80000000"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,5c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM12,19.2c-2.5,0 -4.71,-1.28 -6,-3.22 0.03,-1.99 4,-3.08 6,-3.08 1.99,0 5.97,1.09 6,3.08 -1.29,1.94 -3.5,3.22 -6,3.22z"/>
</vector>
複製程式碼
點選後的效果為:
![圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解](https://i.iter01.com/images/05fcb9d6baae6ebdd15c16a01f875492542b789fa65c844b387c036b6866590c.gif)
七、動態VectorDrawable
動態的VectorDrawable
,也就是AnimatedVectorDrawable
,一般來說,它的整個結構如下圖所示:
![圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解](https://i.iter01.com/images/3f159c7f31f848e9d644ed9cf210ebb6d3054c55d21f2c57ae998e41c68bb532.png)
VectorDrawable
,一般需要提供三種型別的*.xml
檔案,這三個xml
檔案的根標籤分別為:
vector
:影象資源,也就是我們上面討論的靜態vector
,定義於res/drawable
資料夾下。objectAnimator
:定義影象資源中個元素的動畫行為,定義於res/anim
資料夾下。animated - vector
:對vector
中的元素與objectAnimator
進行組合,定義於res/drawable
資料夾下。
7.1 對<group>
標籤進行動畫
下面,我們先看一個簡單的例子,上面我們所談到的三個*.xml
檔案如下:
![圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解](https://i.iter01.com/images/02f98a5c98b7f77d0ea856c2939520c3ca45ee4a6486ed8b0a5a6208bc8a9bc1.png)
7.1.1 vector
檔案
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<group android:name="group_account" android:pivotX="12" android:pivotY="12">
<path
android:fillColor="#FF000000"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,5c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM12,19.2c-2.5,0 -4.71,-1.28 -6,-3.22 0.03,-1.99 4,-3.08 6,-3.08 1.99,0 5.97,1.09 6,3.08 -1.29,1.94 -3.5,3.22 -6,3.22z"/>
</group>
</vector>
複製程式碼
這裡我們生成了一個頭像的Vector
素材,它的影象如下,注意到,我們用一個group
標籤把path
標籤包裹起來,並且給它定義了一個name
屬性為group_account
,這個屬性在後面會用到。
![圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解](https://i.iter01.com/images/c16c68a3a06f66f0d662ea47cd598b4d0743de01dddf3b844bf72c9da1ef6f4a.png)
7.1.2 objectAnimator
檔案
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="500"
android:propertyName="rotation"
android:repeatCount="infinite"
android:valueFrom="0"
android:valueTo="360"/>
</set>
複製程式碼
objectAnimator
的定義和屬性動畫是相同的,我們需要指定需要變換的屬性,也就是propertyName
,並通過valueFrom/valueTo
指定變化的起點值和終點值,這裡我們選擇了採用無限迴圈的方式來變換目標的rotation
屬性。
7.1.3 animated-vector
檔案
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/account_vector">
<target
android:animation="@anim/account_object_animator"
android:name="group_account"/>
</animated-vector>
複製程式碼
animated-vector
和vector
是一一對應的關係,因此需要在根標籤中指定android:drawable
,也就是在7.1.1
中的vector
檔案。
而每一個target
標籤是內是成對的name - animation
屬性,name
就是在7.1.1
中宣告的group
的name
,而animation
則是在7.1.2
中定義的動畫檔案。
如果objectAnimator
所指定的屬性在name
所對應的標籤中沒有,那麼不會發生任何變化。
7.1.4 啟動動畫
首先,在佈局的xml
檔案中,把imageView
的src
指定為7.1.3
中的animate-vector
:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal">
<ImageView
android:id="@+id/iv_dynamic"
android:src="@drawable/account_animated_vector"
android:text="UserName"
android:layout_width="50dp"
android:layout_height="50dp"/>
</LinearLayout>
複製程式碼
在程式碼中,需要手動獲得這個vectorDrawable
,然後啟動動畫:
public class VectorDrawableActivity extends AppCompatActivity {
private ImageView mAnimateView;
private AnimatedVectorDrawable mAnimatedVectorDrawable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_vector_drawable);
mAnimateView = (ImageView) findViewById(R.id.iv_dynamic);
mAnimatedVectorDrawable = (AnimatedVectorDrawable) mAnimateView.getDrawable();
mAnimateView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mAnimatedVectorDrawable.start();
}
});
}
}
複製程式碼
效果如下:
![圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解](https://i.iter01.com/images/dabc0ed819d79acc0ea76c4149a6e9c61a165c3cc10acee03395b158bc295f63.gif)
7.2 對<path>
標籤中的屬性進行動畫
在7.1
中,演示瞭如何對group
標籤的屬性進行變換,下面,我們再演示一下如何對path
標籤中的屬性進行變換。和前面類似,我們依然需要三種類性的*.xml
檔案
![圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解](https://i.iter01.com/images/02afdf24957e07227d6cac4bf4b7445d260f7bb8a01d03bbb9c7da4028d3f4a5.png)
7.2.1 vector
檔案
<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:name="path_check"
android:fillColor="#FF000000"
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
</vector>
複製程式碼
這裡,同樣需要給path
指定一個名字,用於後面和objectAnimator
進行關聯,它的素材為:
![圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解](https://i.iter01.com/images/8256011638c5c0cd1118bc43230bf3105e7d316d354c14e3f5263f0809364171.png)
7.2.2 objectAnimator
檔案
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="500"
android:propertyName="trimPathEnd"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType"/>
</set>
複製程式碼
這裡,我們選擇的是path
標籤下的trimPathEnd
屬性,它表示從Path
終點的位置去除Path
,與之對應的還有trimPathStart
屬性,它表示從Path
起點的位置去除Path
,而trimPathOffset
則可以改變Path
的起點,這三個值的取值範圍都是0~1
。
7.2.3 animated-vector
檔案
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/check_vector">
<target
android:animation="@anim/check_object_animator"
android:name="path_check"/>
</animated-vector>
複製程式碼
效果如下:
![圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解](https://i.iter01.com/images/1a6829ce361c0b693b29d0fd1fbc0c58bb67be8a5fb06307b56cd282e3aafa75.gif)
7.3 <path>
之間切換
除了上面普通的屬性之外,還支援對<path>
標籤下的<pathData>
進行改變,系統會比較兩個pathData
之間的差別,並自動產生合適的動畫。需要注意,它要求這兩個pathData
的點座標的個數是相同的。
7.3.1 Vector
檔案
這裡,我們需要生成兩個vectorDrawable
,首先是起始的VectorDrawable
:
<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:name="path_arrow_down"
android:fillColor="#FF000000"
android:pathData="M7,10l5,5 5,-5z"/>
</vector>
複製程式碼
它的素材為:
![圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解](https://i.iter01.com/images/c65ad2b74cf783e82a7626966de3e57bc6fe800f7b4e2e084ca478ef625169f6.png)
VectorDrawable
:
<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="M7,14l5,-5 5,5z"/>
</vector>
複製程式碼
它對應的素材為:
![圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解](https://i.iter01.com/images/1d48fc8ffb06d6eebe72c89ab567325468082c187f937844b4613c47864631b5.png)
7.3.2 objectAnimator
檔案
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="500"
android:propertyName="pathData"
android:valueFrom="M7,10l5,5 5,-5z"
android:valueTo="M7,14l5,-5 5,5z"
android:valueType="pathType"/>
</set>
複製程式碼
這裡的propertyName
和valueType
需要分別定義為pathData
和pathType
,而起點和終點的值就是我們在7.3.1
生成的兩個VectorDrawable
所對應的pathData
屬性的值。
7.3.3 animated-vector
檔案
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/arrow_down_vector">
<target
android:animation="@anim/arrow_down_object_animator"
android:name="path_arrow_down"/>
</animated-vector>
複製程式碼
最終的效果為:
![圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解](https://i.iter01.com/images/f70207e1c8cde84f8a714e75d2ca24e07114271b95bb64df98ab4260b7b512ee.gif)
八、VectorDrawable
的效能
關於VectorDrawable
的效能問題,Android Vector 曲折的相容之路 這篇文章說的很好,因此直接引用過來了:
Bitmap
的繪製效率並不一定會比Vector
高,它們有一定的平衡點,當Vector
比較簡單時,其效率是一定比Bitmap
高的,所以,為了保證Vector
的高效率,Vector
需要更加簡單,PathData
更加標準、精簡,當Vector
影象變得非常複雜時,就需要使用Bitmap
來代替了。
Vector
適用於ICON
、Button
、ImageView
的圖示等小的ICON
,或者是需要的動畫效果,由於Bitmap
在GPU
中有快取功能,而Vector
並沒有,所以Vector
影象不能做頻繁的重繪Vector
影象過於複雜時,不僅僅要注意繪製效率,初始化效率也是需要考慮的重要因素SVG
載入速度會快於PNG
,但渲染速度會慢於PNG
,畢竟PNG
有硬體加速,但平均下來,載入速度的提升彌補了繪製的速度缺陷。
九、參考文獻
1. Android Vector 曲折的相容之路 2. VectorDrawable 怎麼玩 3. Android 使用向量圖(SVG, VectorDrawable)實踐篇 4. SVG - 百度百科 5. Android 中的 SVG 影象的各個屬性意義