Android Vector曲折的兼容之路

Android Vector曲折的兼容之路

兩年前寫書的時(shí)候戳寸,就在研究Android L提出的Vector,可研究下來發(fā)現(xiàn)袖瞻,完全不具備兼容性聋迎,相信這也是它沒有被廣泛使用的一個(gè)原因砌庄,經(jīng)過Google的不懈努力娄昆,現(xiàn)在Vector終于迎來了它的春天萌焰。

4.jpg

在文章后面奶卓,會(huì)給出本文的Demo和效果圖夺姑,并開源在Github

Vector Drawable

Android 5.0發(fā)布的時(shí)候盏浙,Google提供了Vector的支持废膘。Vector Drawable相對(duì)于普通的Drawable來說丐黄,有以下幾個(gè)好處:

  • Vector圖像可以自動(dòng)進(jìn)行適配灌闺,不需要通過分辨率來設(shè)置不同的圖片
  • Vector圖像可以大幅減少圖像的體積菩鲜,同樣一張圖接校,用Vector來實(shí)現(xiàn)鹿寻,可能只有PNG的幾十分之一
  • 使用簡(jiǎn)單毡熏,很多設(shè)計(jì)工具痢法,都可以直接導(dǎo)出SVG圖像财搁,從而轉(zhuǎn)換成Vector圖像
  • 功能強(qiáng)大尖奔,不用寫很多代碼就可以實(shí)現(xiàn)非常復(fù)雜的動(dòng)畫
  • 成熟提茁、穩(wěn)定茴扁,前端已經(jīng)非常廣泛的進(jìn)行使用了

Vector圖像剛發(fā)布的時(shí)候峭火,是只支持Android 5.0+的,對(duì)于Android pre-L的系統(tǒng)來說纤勒,并不能使用摇天,所以泉坐,可以說那時(shí)候的Vector并沒有什么卵用腕让。不過自從AppCompat 23.2之后纯丸,Google對(duì)p-View的Android系統(tǒng)也進(jìn)行了兼容俊扭,也就是說萨惑,Vector可以使用于Android 2.1以上的所有系統(tǒng)庸蔼,只需要引用com.android.support:appcompat-v7:23.2.0以上的版本就可以了朱嘴,這時(shí)候萍嬉,Vector應(yīng)該算是迎來了它的春天壤追。

如何獲得Vector圖像

概念

首先行冰,需要講解兩個(gè)概念——SVG和Vector伶丐。

SVG哗魂,即Scalable Vector Graphics 矢量圖录别,這種圖像格式在前端中已經(jīng)使用的非常廣泛了组题,詳見WIKI:https://en.wikipedia.org/wiki/Scalable_Vector_Graphics

Vector崔列,在Android中指的是Vector Drawable,也就是Android中的矢量圖趣效,詳見:https://developer.android.com/reference/android/graphics/drawable/VectorDrawable.html

因此跷敬,可以說Vector就是Android中的SVG實(shí)現(xiàn)西傀,因?yàn)锳ndroid中的Vector并不是支持全部的SVG語法拥褂,也沒有必要饺鹃,因?yàn)橥暾腟VG語法是非常復(fù)雜的间雀,但已經(jīng)支持的SVG語法已經(jīng)夠用了惹挟,特別是Path語法连锯,幾乎是Android中Vector的標(biāo)配运怖,詳細(xì)可以參考:http://www.w3.org/TR/SVG/paths.html

Vector語法簡(jiǎn)介

Android以一種簡(jiǎn)化的方式對(duì)SVG進(jìn)行了兼容摇展,這種方式就是通過使用它的Path標(biāo)簽吗购,通過Path標(biāo)簽捻勉,幾乎可以實(shí)現(xiàn)SVG中的其它所有標(biāo)簽踱启,雖然可能會(huì)復(fù)雜一點(diǎn)埠偿,但這些東西都是可以通過工具來完成的冠蒋,所以朽寞,不用擔(dān)心寫起來會(huì)很復(fù)雜斩郎。

Path指令解析如下所示:

  1. 支持的指令:
  • M = moveto(M X,Y) :將畫筆移動(dòng)到指定的坐標(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)閉路徑
  1. 使用原則:
  • 坐標(biāo)軸為以(0,0)為中心肘迎,X軸水平向右妓布,Y軸水平向下
  • 所有指令大小寫均可炼幔。大寫絕對(duì)定位肛著,參照全局坐標(biāo)系跺讯;小寫相對(duì)定位刀脏,參照父容器坐標(biāo)系
  • 指令和數(shù)據(jù)間的空格可以省略
  • 同一指令出現(xiàn)多次可以只用一個(gè)

注意愈污,'M'處理時(shí)暂雹,只是移動(dòng)了畫筆杭跪, 沒有畫任何東西。 它也可以在后面給出上同時(shí)繪制不連續(xù)線系奉。

關(guān)于這些語法缺亮,開發(fā)者需要的并不是全部精通迷雪,而是能夠看懂即可虫蝶,其它的都可以交給工具來實(shí)現(xiàn)能真。

從PNG到SVG

  • 設(shè)計(jì)師

要從一般使用的PNG圖像轉(zhuǎn)換到SVG圖像疼约,對(duì)于設(shè)計(jì)師來說蝙泼,并不是一件難事织鲸,因?yàn)榇蟛糠值脑O(shè)計(jì)工具(PS搂擦、Illustrator等等)都支持導(dǎo)出各種格式的圖像瀑踢,如PNG橱夭、JPG桑逝,當(dāng)然呈础,也包括SVG橱健,因此拘荡,設(shè)計(jì)師可以完全按照原有的方式進(jìn)行設(shè)計(jì)珊皿,只是最后導(dǎo)出的時(shí)候蟋定,選擇SVG即可扼仲。

  • 程序員

不要求開發(fā)者都去學(xué)習(xí)使用這些設(shè)計(jì)工具抄淑,開發(fā)者可以利用一些工具矗愧,自己轉(zhuǎn)換一些比較基礎(chǔ)的圖像唉韭,http://inloop.github.io/svg2android/ 就是這樣一個(gè)非常牛逼的網(wǎng)站纽哥,可以在線將普通圖像轉(zhuǎn)換為Android Vector Drawable春塌。如圖所示:

5.png

或者只壳,還可以使用SVG的編輯器來進(jìn)行SVG圖像的編寫,例如http://editor.method.ac/

6.png

使用Android Studio

利用Android Studio的Vector Asset惕艳,可以非常方便的創(chuàng)建Vector圖像远搪,甚至可以直接通過本地的SVG圖像來生成Vector圖像谁鳍,如圖所示:

2.png

進(jìn)去之后绷柒,就可以生成Vector圖像涮因,如圖所示:

3.png

Google的兼容之路

只兼容L+

Vector是在Android L中提出來的新概念郊楣,所以在剛開始的時(shí)候是只兼容L+的净蚤。

Gradle Plugin 1.5的兼容

從Gradle Plugin 1.5開始今瀑,Google支持了一種兼容方式橘荠,即在Android L之上,使用Vector贮懈,而在L之下朵你,則使用Gradle將Vector生成PNG圖像抡医。

Android gradle plugin 1.5發(fā)布以后大脉,加入了一個(gè)跟VectorDrawable有關(guān)的新功能镰矿。Android build tools 提供了另外一種解決兼容性的方案,如果編譯的版本是5.0之前的版本棍矛,那么build tools 會(huì)把VectorDrawable生成對(duì)應(yīng)的png圖片安疗,這樣在5.0以下的版本則使用的是生成的png圖,而在5.0以上的版本中則使用VectorDrawable.在build.gradle添加generatedDensities配置够委,可以配置生成的png圖片的密度荐类。

AppCompat23.2的兼容

從AppCompat23.2開始,Google開始支持在低版本上使用Vector茁帽。

靜態(tài)Vector圖像

我們有很多方法能夠得到這些Vector玉罐,那么如何使用它們呢,Android 5.0以上的使用就不講了,不太具有普遍代表性,我們從pre-L版本的兼容開始做起扭屁。

pre-L版本兼容

VectorDrawableCompat依賴于AAPT的一些功能艾船,它能保持最近矢量圖使用的添加的屬性ID,以便他們可以被pre-L版本之前的引用浴井。

在Android 5.0之前使用Vector,需要aapt來對(duì)資源進(jìn)行一些處理,這一過程可以在aapt的配置中進(jìn)行設(shè)置剥啤,如果沒有啟用這樣一個(gè)flag防楷,那么在5.0以下的設(shè)備上運(yùn)行就會(huì)發(fā)生android.content.res.Resources$NotFoundException。

首先,你需要在項(xiàng)目的build.gradle腳本中羊异,增加對(duì)Vector兼容性的支持平道,代碼如下所示:

使用Gradle Plugin 2.0以上:

android {

    defaultConfig {
        vectorDrawables.useSupportLibrary = true
    }
}

使用Gradle Plugin 2.0以下袋哼,Gradle Plugin 1.5以上:

android {
  defaultConfig {
    // Stops the Gradle plugin’s automatic rasterization of vectors
    generatedDensities = []
  }
  // Flag to tell aapt to keep the attribute ids around
  aaptOptions {
    additionalParameters "--no-version-vectors"
  }
}

像前面提到的,這種兼容方式實(shí)際上是先關(guān)閉AAPT對(duì)pre-L版本使用Vector的妥協(xié)骄酗,即在L版本以上,使用Vector,而在pre-L版本上,使用Gradle生成相應(yīng)的PNG圖片愿待,generatedDensities這個(gè)數(shù)組,實(shí)際上就是要生成PNG的圖片分辨率的數(shù)組,使用appcompat后就不需要這樣了。

當(dāng)然沼溜,最重要的還是添加appcompat的支持:

compile 'com.android.support:appcompat-v7:23.4.0'

同時(shí)找都,確保你使用的是AppCompatActivity而不是普通的Activity。

Vector圖像

一個(gè)基本的Vector圖像,實(shí)際上也是一個(gè)xml文件,如下所示:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="200dp"
        android:height="200dp"
        android:viewportHeight="500"
        android:viewportWidth="500">

    <path
        android:name="square"
        android:fillColor="#000000"
        android:pathData="M100,100 L400,100 L400,400 L100,400 z"/>

</vector>

顯示如圖所示:

7.png

這里需要解釋下這里的幾個(gè)標(biāo)簽:

  • android:width \ android:height:定義圖片的寬高
  • android:viewportHeight \ android:viewportWidth:定義圖像被劃分的比例大小亲澡,例如例子中的500其弊,即把200dp大小的圖像劃分成500份绩社,后面Path標(biāo)簽中的坐標(biāo)拌滋,就全部使用的是這里劃分后的坐標(biāo)系統(tǒng)吠卷。

這樣做有一個(gè)非常好的作用路操,就是將圖像大小與圖像分離,后面可以隨意修改圖像大小,而不需要修改PathData中的坐標(biāo)。

  • android:fillColor:PathData中的這些屬性就不詳細(xì)講了舀射,與Canvas繪圖的屬性基本類似。

在控件中使用

有了靜態(tài)的Vector圖像,就可以在控件中使用了。

可以發(fā)現(xiàn)安岂,這里我們使用的都是普通的ImageView败许,好像并不是AppcomatImageView盟戏,這是因?yàn)槭褂昧薃ppcomat后,系統(tǒng)會(huì)自動(dòng)把ImageView轉(zhuǎn)換為AppcomatImageView。

ImageView\ImageButton

對(duì)于ImageView這樣的控件制圈,要兼容Vector圖像齐板,只需要將之前的android:src屬性,換成app:srcCompat即可又厉,示例代碼如下所示:

<ImageView
    android:id="@+id/iv"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:srcCompat="@drawable/vector_image"/>

在代碼中設(shè)置的話宣羊,代碼如下所示:

ImageView iv = (ImageView) findViewById(R.id.iv);
iv.setImageResource(R.drawable.vector_image);

setBackgroundResource也是可以設(shè)置Vector的API

Button

Button并不能直接使用app:srcCompat來使用Vector圖像,需要通過Selector來進(jìn)行使用,首先冒掌,創(chuàng)建兩個(gè)圖像,用于Selector的兩個(gè)狀態(tài),代碼如下所示:

selector1.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="M14.59,8L12,10.59 9.41,8 8,9.41 10.59,12 8,14.59 9.41,16 12,13.41 14.59,16 16,14.59 13.41,12 16,9.41 14.59,8zM12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>

selector2.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,15h2v2h-2zM11,7h2v6h-2zM11.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,8z"/>
</vector>

selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/selector1" android:state_pressed="true"/>
    <item android:drawable="@drawable/selector2"/>
</selector>

非常簡(jiǎn)單,只是把普通的Selector中的圖像換成了Vector圖像而已逮走,接下來蘸鲸,在Button中使用這個(gè)Selector即可:

<Button
    android:id="@+id/btn"
    android:layout_width="70dp"
    android:layout_height="70dp"
    android:background="@drawable/selector"/>

然后運(yùn)行鼻疮,如果你認(rèn)為可以運(yùn)行,那就是太天真了,都說了是兼容增蹭,怎么能沒有坑呢椰憋,這里就是一個(gè)坑……

這個(gè)坑實(shí)際上是有歷史淵源的漆枚,Google的一位開發(fā)者在博客中寫到:

First up, this functionality was originally released in 23.2.0, but then we found some memory usage and Configuration updating issues so we it removed in 23.3.0. In 23.4.0 (technically a fix release) we’ve re-added the same functionality but behind a flag which you need to manually enable.

實(shí)際上,他們的這個(gè)改動(dòng)螺戳,就影響了類似DrawableContainers(DrawableContainers which reference other drawables resources which contain only a vector resource)這樣的類堕伪,它的一個(gè)典型,就是Selector(StateListDrawable也是)悠瞬。這個(gè)開發(fā)者在文中提到的flag,就是下面的這段代碼疮薇,放在Activity的前面就可以了:

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

開啟這個(gè)flag后,你就可以正常使用Selector這樣的DrawableContainers了箫锤。同時(shí)讼稚,你還開啟了類似android:drawableLeft這樣的compound drawable的使用權(quán)限浅蚪,以及RadioButton的使用權(quán)限饿这,以及ImageView’s src屬性肌割。

RadioButton

RadioButton的Button同樣可以定義,代碼如下所示:

<RadioButton
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:button="@drawable/selector"/>

動(dòng)態(tài)Vector基礎(chǔ)

動(dòng)態(tài)Vector才是Android Vector Drawable的精髓所在

動(dòng)態(tài)的Vector需要通過animated-vector標(biāo)簽來進(jìn)行實(shí)現(xiàn),它就像一個(gè)粘合劑狂芋,將控件與Vector圖像粘合在了一起种吸,一個(gè)基礎(chǔ)的animated-vector代碼如下所示:

<animated-vector
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/XXXXX1">

    <target
        android:name="left"
        android:animation="@animator/XXXXX2"/>

</animated-vector>

實(shí)際上這里面只有兩個(gè)重點(diǎn)是需要關(guān)注的求豫,XXXXX1和XXXXX2。一個(gè)具體的示例如下所示:

<animated-vector
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_arrow">

    <target
        android:name="left"
        android:animation="@animator/anim_left"/>

    <target
        android:name="right"
        android:animation="@animator/anim_right"/>

</animated-vector>

這里表示目標(biāo)圖像是drawable/ic_arrow,對(duì)left匾旭、right分別使用了anim_left居兆、anim_right動(dòng)畫。這里的name屬性钱豁,就是在靜態(tài)Vector圖像中g(shù)roup或者path標(biāo)簽的name屬性。

animated-vector標(biāo)簽在現(xiàn)在的Android Studio中實(shí)際上是會(huì)報(bào)錯(cuò)的卷仑,但這個(gè)并不影響編譯和運(yùn)行,屬于Android Studio的Bug。

目標(biāo)圖像

XXXXX1是目標(biāo)Vector圖像俭缓,也就是靜態(tài)的Vector圖像寝优,例如:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="120dp"
        android:height="120dp"
        android:viewportHeight="24.0"
        android:viewportWidth="24.0">

    <group android:name="left">
        <path
            android:fillColor="#FF000000"
            android:pathData="M9.01,14L2,14v2h7.01v3L13,15l-3.99,-4v3"/>
    </group>

    <group android:name="right">
        <path
            android:fillColor="#FF000000"
            android:pathData="M14.99,13v-3L22,10L22,8h-7.01L14.99,5L11,9l3.99,4"/>
    </group>

</vector>

可以發(fā)現(xiàn),這里的Vector圖像比之前我們看見的要多了一個(gè)group標(biāo)簽坯钦。group標(biāo)簽的作用有兩個(gè):

  • 對(duì)Path進(jìn)行分組鲁豪,由于我們后面需要針對(duì)Path進(jìn)行動(dòng)畫船惨,所以可以讓具有同樣動(dòng)畫效果的Path在同一個(gè)Group中
  • 拓展動(dòng)畫效果,單個(gè)的path標(biāo)簽是沒有translateX和translateY屬性的樟氢,因此無法使用屬性動(dòng)畫來控制path translateY眶掌,而group標(biāo)簽是有的,所以我們需要先將相關(guān)的path標(biāo)簽元素包裹在一個(gè)個(gè)的group標(biāo)簽中.

動(dòng)畫效果

XXXXX2實(shí)際上就是模板要實(shí)現(xiàn)的動(dòng)畫巴碗,動(dòng)畫效果實(shí)際上就是基礎(chǔ)的屬性動(dòng)畫朴爬,例如:

anim_left.xml

<objectAnimator
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:interpolator="@android:interpolator/anticipate_overshoot"
    android:propertyName="translateX"
    android:repeatCount="infinite"
    android:repeatMode="reverse"
    android:valueFrom="0"
    android:valueTo="-10"
    android:valueType="floatType"/>

anim_right.xml

<objectAnimator
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:interpolator="@android:interpolator/anticipate_overshoot"
    android:propertyName="translateX"
    android:repeatCount="infinite"
    android:repeatMode="reverse"
    android:valueFrom="0"
    android:valueTo="10"
    android:valueType="floatType"/>

在代碼中使用

ImageView imageView = (ImageView) findViewById(R.id.iv);
AnimatedVectorDrawableCompat animatedVectorDrawableCompat = AnimatedVectorDrawableCompat.create(
        this, R.drawable.square_anim
);
imageView.setImageDrawable(animatedVectorDrawableCompat);
((Animatable) imageView.getDrawable()).start();

動(dòng)態(tài)Vector兼容性問題

向下兼容問題

一說到兼容,就不得不提到坑良价,幾乎所有的為了兼容而做的改動(dòng)寝殴,都會(huì)留下一些不可填滿的坑,動(dòng)態(tài)Vector動(dòng)畫也不例外明垢,雖然Google已經(jīng)對(duì)Vector圖像進(jìn)行了Android 2.1以上的兼容,但對(duì)于動(dòng)態(tài)Vector動(dòng)畫市咽,還是有很多限制的痊银,例如:

  • Path Morphing,即路徑變換動(dòng)畫施绎,在Android pre-L版本下是無法使用的溯革。
  • Path Interpolation,即路徑插值器谷醉,在Android pre-L版本只能使用系統(tǒng)的插值器致稀,不能自定義。
  • Path Animation俱尼,即路徑動(dòng)畫抖单,這個(gè)一般使用貝塞爾曲線來代替,所以沒有太大影響遇八。

向上兼容問題

除了在低版本上的兼容性問題矛绘,在L版本以上,也存在兼容性問題刃永,即繼承了AppCompatActivity的界面货矮,如果直接設(shè)置ImageView的srcCompat,那么Path Morphing動(dòng)畫是無法生效的斯够,因?yàn)槟J(rèn)的AppCompatActivity已經(jīng)默認(rèn)使用ImageViewCompat給轉(zhuǎn)換了囚玫,但是AnimatedVectorDrawableCompat是不支持Path Morphing動(dòng)畫的喧锦,所以,在AppCompatActivity界面里面就無效了抓督。

解決辦法很簡(jiǎn)單裸违,即使用代碼來給ImageView添加動(dòng)畫:

ImageView imageView = (ImageView) view;
AnimatedVectorDrawable morphing = (AnimatedVectorDrawable) getDrawable(morphing);
imageView.setImageDrawable(morphing);
if (morphing != null) {
    morphing.start();
}

注意不要使用AnimatedVectorDrawableCompat即可。

抽取string兼容問題

開發(fā)者有時(shí)候?yàn)榱舜a簡(jiǎn)潔可能會(huì)把Vector圖像中的pathData放到string.xml中本昏,然后在Vector圖像中引用string供汛。

但這種方式如果通過生成png來兼容5.0以下機(jī)型的話,會(huì)報(bào)pathData錯(cuò)誤涌穆,編譯器不會(huì)去讀取string.xml怔昨,只能把pathData寫到Vector圖像中,動(dòng)畫文件中也是一樣宿稀,這也是為了兼容做出的犧牲嗎趁舀,不得而知。

其它兼容問題

其它非常奇怪祝沸、詭異矮烹、不能理解的兼容性問題,只能通過版本文件夾的方式來進(jìn)行兼容了罩锐,例如drawable-v21和drawable奉狈,分別創(chuàng)建兩個(gè)文件名相同的資源在兩個(gè)文件夾下,這樣在21以上版本涩惑,會(huì)使用drawable-v21的資源仁期,而其它會(huì)使用drawable下的資源。

動(dòng)態(tài)Vector進(jìn)階

用好ObjectAnimator

所謂Vector動(dòng)畫進(jìn)階竭恬,實(shí)際上就是在利用ObjectAnimator的一些屬性跛蛋,特別是trimPathStart、trimPathEnd這兩個(gè)針對(duì)Vector的屬性(要注意pathData屬性不兼容pre-L)痊硕。

這兩個(gè)屬性的官方文檔如下所示:

android:trimPathStart
The fraction of the path to trim from the start, in the range from 0 to 1.
android:trimPathEnd
The fraction of the path to trim from the end, in the range from 0 to 1.
android:trimPathOffset
Shift trim region (allows showed region to include the start and end), in the range from 0 to 1.

其實(shí)很簡(jiǎn)單赊级,就是一個(gè)圖像的截取,設(shè)置一個(gè)比例即可岔绸,即當(dāng)前繪制多少比例的圖像理逊,其余部分不繪制,Start和End分別就是從PathData的Start和End開始算亭螟,大家參考幾個(gè)例子就能理解了挡鞍。

理解Path Morph

Path Morph動(dòng)畫是Vector動(dòng)畫的一個(gè)高級(jí)使用,說到底预烙,也就是兩個(gè)PathData的轉(zhuǎn)換墨微,但是這種轉(zhuǎn)換并不是隨心所欲的,對(duì)于兩個(gè)PathData扁掸,它們能進(jìn)行Path Morph的前提是翘县,它們具有相同個(gè)數(shù)的關(guān)鍵點(diǎn)最域,即兩個(gè)路徑的變換,只是關(guān)鍵點(diǎn)的坐標(biāo)變化锈麸,掌握了這一個(gè)基本原理镀脂,實(shí)現(xiàn)Path Morph就非常容易了。

學(xué)習(xí)Vector

在Github上我開源了一個(gè)Vector的動(dòng)畫Demo庫(kù)忘伞,地址如下所示:

https://github.com/xuyisheng/VectorDemo

這個(gè)Demo分為兩部分薄翅,一部分是可以兼容Android pre-L版本和L+版本的Vector動(dòng)畫,另一部分(通過Actionbar的按鈕切換)是只能兼容L+的Vector動(dòng)畫氓奈。

每個(gè)Vector動(dòng)畫翘魄,基本都包含四部分內(nèi)容,即:

  • Vector:圖像資源
  • Animated-vector:動(dòng)畫舀奶、圖像粘合劑
  • ObjectAnimator:動(dòng)畫資源
  • 代碼:?jiǎn)?dòng)動(dòng)畫

每個(gè)Vector動(dòng)畫通過這四個(gè)部分去進(jìn)行分析暑竟,就非常清晰了。

這里展示下Demo的效果圖:

vector.gif

Vector性能問題

有讀者在文章后面留言育勺,詢問VectorDrawable的性能問題但荤,這里解釋一下。

  1. Bitmap的繪制效率并不一定會(huì)比Vector高涧至,它們有一定的平衡點(diǎn)腹躁,當(dāng)Vector比較簡(jiǎn)單時(shí),其效率是一定比Bitmap高的化借,所以潜慎,為了保證Vector的高效率,Vector需要更加簡(jiǎn)單蓖康,PathData更加標(biāo)準(zhǔn)、精簡(jiǎn)垒手,當(dāng)Vector圖像變得非常復(fù)雜時(shí)蒜焊,就需要使用Bitmap來代替了
  2. Vector適用于ICON、Button科贬、ImageView的圖標(biāo)等小的ICON泳梆,或者是需要的動(dòng)畫效果,由于Bitmap在GPU中有緩存功能榜掌,而Vector并沒有优妙,所以Vector圖像不能做頻繁的重繪
  3. Vector圖像過于復(fù)雜時(shí),不僅僅要注意繪制效率憎账,初始化效率也是需要考慮的重要因素
  4. SVG加載速度會(huì)快于PNG套硼,但渲染速度會(huì)慢于PNG,畢竟PNG有硬件加速胞皱,但平均下來邪意,加載速度的提升彌補(bǔ)了繪制的速度缺陷九妈。
    Google的這個(gè)視頻中,已經(jīng)對(duì)Vector的效率問題做了解釋雾鬼,可以參考下:

https://www.youtube.com/watch?v=wlFVIIstKmA&feature=youtu.be&t=6m3s

參考

https://medium.com/@shemag8/animated-vector-drawable-e4d7743d372c#.3vkt12j20
https://github.com/jpuderer/AnimatedButton

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末萌朱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子策菜,更是在濱河造成了極大的恐慌晶疼,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件又憨,死亡現(xiàn)場(chǎng)離奇詭異翠霍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)竟块,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門壶运,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人浪秘,你說我怎么就攤上這事蒋情。” “怎么了耸携?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵棵癣,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我夺衍,道長(zhǎng)狈谊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任沟沙,我火速辦了婚禮河劝,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘矛紫。我一直安慰自己赎瞎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布颊咬。 她就那樣靜靜地躺著务甥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪喳篇。 梳的紋絲不亂的頭發(fā)上敞临,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音麸澜,去河邊找鬼挺尿。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的票髓。 我是一名探鬼主播攀涵,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼洽沟!你這毒婦竟也來了以故?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤裆操,失蹤者是張志新(化名)和其女友劉穎怒详,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體踪区,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡昆烁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缎岗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片静尼。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖传泊,靈堂內(nèi)的尸體忽然破棺而出鼠渺,到底是詐尸還是另有隱情,我是刑警寧澤眷细,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布拦盹,位于F島的核電站,受9級(jí)特大地震影響溪椎,放射性物質(zhì)發(fā)生泄漏普舆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一校读、第九天 我趴在偏房一處隱蔽的房頂上張望沼侣。 院中可真熱鬧,春花似錦歉秫、人聲如沸华临。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至揭厚,卻和暖如春却特,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背筛圆。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工裂明, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人太援。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像仙蛉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子荠瘪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容