圖片壓縮知識梳理(6) VectorDrawable 及 AnimatedVectorDrawable 使用詳解

1、Vector優勢

VectorDrawable主要有兩個優勢:屏幕自適應體積小android

  • 若是咱們使用的是普通的png或者jpg圖片,那麼爲了能讓圖片在不一樣分辨率的機型上可以很好地展示,一般會在各個drawable文件夾下放置不一樣分辨率大小的圖片文件,而VectorDrawable則不須要,僅僅只使用一套資源,就可以適應任何分辨率的手機。
  • 對於某些圖片,VectorDrawable素材的大小要比pngjpg小不少。

2、SVGVector的基本概念

下面,咱們先介紹一下SVGVectorDrawable的基本概念:緩存

  • SVG:它並非Android平臺特有的概念,它的全稱爲可縮放矢量圖形,簡單的來講,就是用於描述二維矢量圖形的圖形格式,更加詳細的解釋能夠參考:SVG - 百度百科
  • VectorDrawable:它是Android當中的SVG實現,它並不支持SVG的所有語法,只是支持部分有必要的部分。

3、獲取VectorDrawable

俗話說的好,巧婦難爲無米炊,這一節咱們就來介紹一下如何得到一個VectorDrawable,通常獲取的方式有如下三種方式:bash

  • 先獲取SVG素材,再經過工具轉換成爲VectorDrawable
  • 經過Android Studio中的素材庫,直接獲取VectorDrawable
  • 根據Vector的語法,本身描述

3.1 先獲取SVG素材,再經過工具轉換成爲VectorDrawable

首先獲取SVG素材,再將它轉換成爲VectorDrawable是最經常使用的方式,而SVG素材的獲取又有如下幾種途徑:app

  • 網站直接下載SVG圖像
  • UI設計師使用專業的工具導出
  • 經過 VectorMagic 軟件,將pngjpg素材轉換爲SVG圖像

對於我的開發者而言,通常都會採用第一種方式,咱們這裏也只介紹第一種方式。不少文章都推薦過這個網站:iconFront - 阿里巴巴,它提供了SVGPNG素材的直接下載: eclipse

下載完畢以後,在 Android StudioNew選項中,選擇 Vector Asset
打開以後,選擇 Local file,並打開咱們下載後的圖像,再選擇 next保存到指定的文件夾:
最後,咱們會獲得一個 *.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

仍是在上面的那個界面,咱們勾選另一個選項: ide

這裏面有 Material Design提供的素材庫:
經過這種方式,一樣能夠獲取到一個 *.xmlVectorDrawable

<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.13.2當中,咱們能夠看到,最終VectorDrawable都是用一個*.xml來表示的,那麼,咱們固然能夠根據SVG的語法,來編寫一個xml文件,經過pathData屬性進行描述,不過這種方式較爲繁瑣,通常不會採用。工具

4、Vector語法

雖說大多數狀況下,咱們不會徹底手動去編寫Vectorxml文件,可是,對於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>組合在一塊兒,進行相同的處理。性能

更多的屬性能夠查閱下面這兩篇文章:gradle

VectorDrawable 詳解 Android 中的 SVG 圖像的各個屬性意義

5、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相關的兩個包爲:

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
    }
}
複製代碼

關於更多兼容性的問題,能夠查看下面這篇文章

Android Vector 曲折的兼容之路

6、靜態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>
複製代碼

咱們能夠應用於:

  • ImageViewsrc
  • Viewbackground
  • TextViewdrawable
<?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>
複製代碼

點擊後的效果爲:

7、動態VectorDrawable

動態的VectorDrawable,也就是AnimatedVectorDrawable,通常來講,它的整個結構以下圖所示:

爲了實現動態的 VectorDrawable,通常須要提供三種類型的 *.xml文件,這三個 xml文件的根標籤分別爲:

  • vector:圖像資源,也就是咱們上面討論的靜態vector,定義於res/drawable文件夾下。
  • objectAnimator:定義圖像資源中個元素的動畫行爲,定義於res/anim文件夾下。
  • animated - vector:對vector中的元素與objectAnimator進行組合,定義於res/drawable文件夾下。

7.1 對<group>標籤進行動畫

下面,咱們先看一個簡單的例子,上面咱們所談到的三個*.xml文件以下:

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,這個屬性在後面會用到。

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-vectorvector是一一對應的關係,所以須要在根標籤中指定android:drawable,也就是在7.1.1中的vector文件。 而每個target標籤是內是成對的name - animation屬性,name就是在7.1.1中聲明的groupname,而animation則是在7.1.2中定義的動畫文件。

若是objectAnimator所指定的屬性在name所對應的標籤中沒有,那麼不會發生任何變化。

7.1.4 啓動動畫

首先,在佈局的xml文件中,把imageViewsrc指定爲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();
            }
        });
    }
}
複製代碼

效果以下:

7.2 對<path>標籤中的屬性進行動畫

7.1中,演示瞭如何對group標籤的屬性進行變換,下面,咱們再演示一下如何對path標籤中的屬性進行變換。和前面相似,咱們依然須要三種類性的*.xml文件

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進行關聯,它的素材爲:

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>
複製代碼

效果以下:

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>
複製代碼

它的素材爲:

接着是終點的 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>
複製代碼

它對應的素材爲:

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>
複製代碼

這裏的propertyNamevalueType須要分別定義爲pathDatapathType,而起點和終點的值就是咱們在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>
複製代碼

最終的效果爲:

8、VectorDrawable的性能

關於VectorDrawable的性能問題,Android Vector 曲折的兼容之路 這篇文章說的很好,所以直接引用過來了:

  • Bitmap的繪製效率並不必定會比Vector高,它們有必定的平衡點,當Vector比較簡單時,其效率是必定比Bitmap高的,因此,爲了保證Vector的高效率,Vector須要更加簡單,PathData更加標準、精簡,當Vector圖像變得很是複雜時,就須要使用Bitmap來代替了。
  • Vector適用於ICONButtonImageView的圖標等小的ICON,或者是須要的動畫效果,因爲BitmapGPU中有緩存功能,而Vector並無,因此Vector圖像不能作頻繁的重繪
  • Vector圖像過於複雜時,不只僅要注意繪製效率,初始化效率也是須要考慮的重要因素
  • SVG加載速度會快於PNG,但渲染速度會慢於PNG,畢竟PNG有硬件加速,但平均下來,加載速度的提高彌補了繪製的速度缺陷。

9、參考文獻

1. Android Vector 曲折的兼容之路 2. VectorDrawable 怎麼玩 3. Android 使用矢量圖(SVG, VectorDrawable)實踐篇 4. SVG - 百度百科 5. Android 中的 SVG 圖像的各個屬性意義

相關文章
相關標籤/搜索