Android高級動畫(2)

目錄

Android高級動畫(1)http://www.reibang.com/p/48554844a2db
Android高級動畫(2)http://www.reibang.com/p/89cfd9042b1e
Android高級動畫(3)http://www.reibang.com/p/d6cc8d218900
Android高級動畫(4)http://www.reibang.com/p/91f8363c3a8c

來點硬貨

前面一篇文章已經(jīng)講了Android中大部分的動畫框架膘螟,回顧一下有:Tween動畫,屬性動畫胎许,幀動畫含长,CircularReveal盐股,Activity轉(zhuǎn)場動畫胎源,5.0新轉(zhuǎn)場動畫译株,Interpolator插值器瓜喇,5.0轉(zhuǎn)場動畫分為Explode、Slide歉糜、Fade乘寒、Share四種模式。合理且充分利用這些動畫匪补,我們已經(jīng)可以做出很多優(yōu)美的效果了肃续。

但是今天這篇文章我們來講講大名鼎鼎的矢量動畫黍檩,它顛覆了前面所有的動畫。前面的動畫都是對控件做動畫始锚,而矢量動畫是對圖形做動畫刽酱,矢量動畫可以做出前面任何一個動畫框架都做不到的效果。好了瞧捌,NB就先不吹了棵里,開始我們的學習吧。

從矢量圖形說起

我們平時看到的圖片大多數(shù)都是位圖姐呐,英文名叫 bitmap殿怜,位圖對應(yīng)的格式就是 .bmp,看過bmp的人都知道曙砂,體積那叫一個大啊头谜。。鸠澈。一張小小的Logo都能2M柱告,于是jpg,png這些壓縮格式就出現(xiàn)了笑陈,優(yōu)秀的壓縮算法極大地減少了圖片體積际度。配合索引位圖、灰度圖等手段涵妥,圖片可以壓縮的非常小乖菱,世界一下子變得美好~

但是,開心沒多久蓬网,問題又來了窒所。不管你的壓縮算法有所優(yōu)秀,位圖有2個天生的缺點無法避免:
(1)圖片放大會失真
(2)圖片尺寸越大帆锋,體積越大

不管是做Android開發(fā)還是IOS開發(fā)墩新,我們都需要適配不同分辨率的手機,也就意味著同一個ImageView在不同手機上的圖片分辨率是不同的窟坐,如果我們只用一套圖片海渊,那必然存在放大失真問題。統(tǒng)一的解決方案就是為每一種分辨屏幕準備一套圖片哲鸳。這樣失真的問題解決了臣疑,但是圖片體積又大了。

似乎兩者是不可兼得的徙菠,怎么辦呢讯沈?

靚仔

矢量圖登場

矢量圖不同于位圖是用像素描述圖像的,它是用數(shù)學曲線描述圖形婿奔。所以一張圖片就是對應(yīng)著一系列的數(shù)學曲線缺狠,所以圖片的顯示尺寸和圖片體積無關(guān)问慎。(這里為什么說顯示尺寸,因為矢量圖根本就沒有所謂的尺寸挤茄,就看你把它顯示成多大)如叼,它的體積就是文本文件的大小。并且矢量圖可以無限拉伸不失真穷劈。

先來看一個Android中使用矢量圖的例子:

愛心

哇笼恰,這個愛心有點漂亮~

代碼實現(xiàn):

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="256dp"
        android:height="256dp"
        android:viewportHeight="32"
        android:viewportWidth="32">

    <path
        android:fillColor="#e11c00"
        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>

PS:這個文件非常小,只有670字節(jié)歇终,連1KB都不到社证。而且我們只需要這一個文件,就可以適配所有分辨率评凝,無限拉伸不失真追葡。)

根節(jié)點是vector,width和height屬性是顯示大小奕短,但是實際上這個大小是可以根據(jù)控件改變的宜肉。viewportHeight和viewportWidth也是寬高,它是定義曲線函數(shù)時所參照的寬高篡诽。子節(jié)點path就是定義繪制內(nèi)容的崖飘,fillColor是填充顏色榴捡,pathData是描繪路徑杈女。那么問題來了,pathData中的這一串字母數(shù)字是什么東東吊圾?

SVG

說到這达椰,SVG必須得登場了。SVG就是標準的矢量圖格式项乒,Android中使用矢量圖雖然沒有直接使用SVG圖片啰劲,但是基本格式是和SVG一樣的。

SVG語法
SVG的語法太復雜了檀何,這里不可能全部講一遍蝇裤。為了說明問題,我們就講幾個最基礎(chǔ)的命令频鉴。
M:新建起點栓辜,參數(shù)x,y(M20垛孔, 30)
L:連接直線藕甩,參數(shù)x,y(L30周荐, 20)
H:縱坐標不變狭莱,橫向連線僵娃,參數(shù)x(H20)
V:橫坐標不變,縱向連線腋妙,參數(shù)y(V30)
Q:二次貝塞爾曲線默怨,參數(shù)x1,y1辉阶,x2先壕,y2(Q10,20谆甜,30垃僚,40)
C:三次貝塞爾曲線,參數(shù)x1规辱,y1谆棺,x2,y2罕袋,x3改淑,y3(C10,20浴讯,30朵夏,40,50榆纽, 60)
Z:連接首尾仰猖,閉合曲線,無參數(shù)

掌握以上這些基本命令之后奈籽,我們基本上就可以畫出90%的圖形了饥侵。比如上面demo只用到了三個命令:M、C衣屏、Z躏升,我們整個系列所有demo用到的命令也就只有M、L狼忱、C膨疏、Z。

(至于什么是二次貝塞爾钻弄,什么是三次貝塞爾佃却,如果不了解的話請自行百度,不能再拓展了斧蜕,否則這篇文章要突破萬字了双霍。)

讓矢量圖形動起來

雖然我們已經(jīng)可以繪制漂亮的矢量圖形了,但是我們這個系列是Android高級動畫啊,得動起來洒闸,Android中怎樣才能讓矢量圖形動起來呢染坯?

animated-vector登場

animated-vector從名字上看就是動起來的vector,先看示例:

animated-vector

初始顯示的是三條橫線丘逸,然后從三條橫線的狀態(tài)變化到箭頭单鹿,同時整體旋轉(zhuǎn)360度。

代碼如下:
(1)首先是layout文件深纲,一個普通的ImageView仲锄,src指向一個drawable

<ImageView
    android:id="@+id/imgBtn"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:onClick="startAnim"
    android:src="@drawable/animvectordrawable" />

(2)drawable根節(jié)點是一個animated-vector,drawable參數(shù)用于指定初始顯示的樣子湃鹊,下面兩個target子節(jié)點用于指定動畫儒喊,第一個target是指定了旋轉(zhuǎn)動畫,第二個target指定了path轉(zhuǎn)變動畫币呵。下面我們分別來看下初始的drawable和兩個target怀愧。

<!-- animvectordrawable.xml -->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/vectordrawable" >
    <target
        android:name="rotationGroup"
        android:animation="@anim/rotation" />

    <target
        android:name="v"
        android:animation="@anim/path_morph" />
</animated-vector>

(3)初始drawable,這個根節(jié)點vector就是定義了寬高余赢,第三層path節(jié)點就是初始顯示的矢量圖形芯义,它有填充色和path路徑。

<!-- vectordrawable.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:height="300dp"
    android:width="300dp"
    android:viewportHeight="70"
    android:viewportWidth="70" >

    <group
        android:name="rotationGroup"
        android:pivotX="35"
        android:pivotY="35"
        android:rotation="0.0" >
        <path
            android:name="v"
            android:fillColor="#000000"
            android:pathData="M10,10 L60,10 L60,20 L10,20 Z M10,30 L60,30 
                L60,40 L10,40 Z M10,50 L60,50 L60,60 L10,60 Z" />
    </group>
</vector>

但是外面又包了一層group妻柒,這個是干什么用的呢扛拨?

animated-vector規(guī)定,可以有多個動畫同時進行举塔,但是一個對象上只能加載一個動畫绑警。上面的例子可以看到三條線圖形轉(zhuǎn)變成箭頭圖形,同時旋轉(zhuǎn)360度啤贩,那就要有兩個動畫待秃,一個做path變換拜秧,一個做旋轉(zhuǎn)痹屹。但是兩個動畫不能同時放在一個對象上,所以必須用group包一層枉氮,把path變換動畫放在path對象上志衍,把旋轉(zhuǎn)動畫放在group對象上,從而實現(xiàn)整體的效果聊替。

(4)target1楼肪,這就是一個簡單的屬性動畫,旋轉(zhuǎn)360度

<!-- rotation.xml -->
<objectAnimator
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1500"
    android:propertyName="rotation"
    android:valueFrom="0"
    android:valueTo="360" />

(5)target2惹悄,這個動畫是最神奇的地方春叫,它用于從一個path變換到另一個path,valueFrom指定變換前的path,valueTo指定變換后的path暂殖,propertyName和valueType在這個例子中是固定寫法价匠。

<!-- path_morph.xml -->
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:duration="1500"
        android:propertyName="pathData"
        android:valueFrom="M10,10 L60,10 L60,20 L10,20 Z M10,30 L60,30 L60,40 
            L10,40 Z M10,50 L60,50 L60,60 L10,60 Z"
        android:valueTo="M5,35 L40,0 L47.072,7.072 L12.072,42.072 Z M10,30 L60,30 L60,40 
            L10,40 Z M12.072,27.928 L47.072,62.928 L40,70 L5,35 Z"
        android:valueType="pathType" />
</set>

這里需要重點提下valueFrom和valueTo

valueFrom和valueTo分別指定了變換前的path和變換后的path,它要求前后兩個path必須是同形path
PS:如果兩個path擁有相同的命令數(shù)呛每,并且對應(yīng)位置的命令符相同踩窖,那么這兩個path我們稱之為同形path。
如:
M10,15 L20,20 L25,15 C10,20,20,20,30,10 L50,50 Z
M20,30 L10,10 L15,25 C25,10,30,30,10,20 L35,35 Z

(6)java代碼啟動動畫

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public void startAnim(View view) {
    Drawable drawable = imgBtn.getDrawable();
    ((Animatable) drawable).start();
}

至此晨横,一個簡單的animated-vector就完成了洋腮,估計有人要吐槽了。
“我的天手形,一個動畫要寫這么多代碼啥供?”
是的,這一點木有辦法库糠,矢量動畫本身就比較復雜滤灯。但是別傷心,因為更復雜的還在后面呢曼玩。鳞骤。。

矢量選擇器

animated-vector已經(jīng)很強大了是吧黍判,但是肯定有人發(fā)現(xiàn)問題了豫尽,animated-vector只能從一個path變換到另一個path,不能反向再變回來顷帖。如果我需要在兩個path之間來回變換該怎么辦呢美旧?

靚仔2

animated-selector登場。

selector我們大家都很熟悉了贬墩,用于一個按鈕的點擊效果榴嗅。animated-selector類似,也是用于兩個狀態(tài)的切換陶舞,只不過animated-selector是在兩個path之間來回切換顯示嗽测。

先看演示:

PathMorphing

是不是很酷炫!迫不及待地想知道是怎么實現(xiàn)的肿孵。

(1)首先是Layout唠粥,一個普通的 ImageView,src指向一個 drawable

<ImageView
    android:id="@+id/iv_2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:scaleType="fitCenter"
    android:src="@drawable/heart_twitter" />

(2)再看drawable停做,drawbale是一個animated-selector晤愧,子節(jié)點是兩個item和兩個transition。

<?xml version="1.0" encoding="utf-8"?>
<animated-selector
    xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@+id/state_on"
        android:drawable="@drawable/ic_twitter"
        android:state_checked="true"/>

    <item android:id="@+id/state_off"
        android:drawable="@drawable/ic_heart" />

    <transition
        android:fromId="@id/state_off"
        android:toId="@id/state_on"
        android:drawable="@drawable/avd_heart_to_twitter" />

    <transition
        android:fromId="@id/state_on"
        android:toId="@id/state_off"
        android:drawable="@drawable/avd_twitter_to_heart" />
</animated-selector>

兩個item分別指定了兩種狀態(tài)下要顯示的樣子蛉腌,兩個transition分別指定了當狀態(tài)切換時所做的動畫官份。

具體來說:第一個item指定的是state_on時顯示的樣子只厘,第二個item指定的是state_off時顯示的樣子。第一個transition指定的是從off切換到on時所做的動畫舅巷,第二個transition指定的是從on切換到off時所做的動畫懈凹。

下面來分別看下兩個item和兩個transition

(3)兩個item

<?xml version="1.0" encoding="UTF-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="150dp"
        android:height="150dp"
        android:viewportHeight="24.0"
        android:viewportWidth="24.0">

    <group
        android:name="groupTwitter"
        android:pivotX="12"
        android:pivotY="12">

        <path
            android:name="twitter"
            android:fillColor="#C2185B"
            android:pathData="M 22.46,6.0 l 0.0,0.0 C 21.69,6.35,20.86,6.58,20.0,6.69 
            C 20.88,6.16,21.56,5.32,21.88,4.31 c 0.0,0.0,0.0,0.0,0.0,0.0 
            C 21.05,4.81,20.13,5.16,19.16,5.36 C 18.37,4.5,17.26,4.0,16.0,4.0 
            c 0.0,0.0,0.0,0.0,0.0,0.0 L 16.0,4.0 C 13.65,4.0,11.73,5.92,11.73,8.29 
            C 11.73,8.63,11.77,8.96,11.84,9.27 C 8.28,9.09,5.11,7.38,3.0,4.79 
            C 2.63,5.42,2.42,6.16,2.42,6.94 C 2.42,8.43,3.17,9.75,4.33,10.5 
            C 3.62,10.5,2.96,10.3,2.38,10.0 C 2.38,10.0,2.38,10.0,2.38,10.03 
            C 2.38,12.11,3.86,13.85,5.82,14.24 C 5.46,14.34,5.08,14.39,4.69,14.39 
            C 4.42,14.39,4.15,14.36,3.89,14.31 C 4.43,16.0,6.0,17.26,7.89,17.29 
            C 6.43,18.45,4.58,19.13,2.56,19.13 C 2.22,19.13,1.88,19.11,1.54,19.07 
            C 3.44,20.29,5.7,21.0,8.12,21.0 C 16.0,21.0,20.33,14.46,20.33,8.79 
            C 20.33,8.6,20.33,8.42,20.32,8.23 C 21.16,7.63,21.88,6.87,22.46,6.0 L 22.46,6.0"/>
    </group>
</vector>
<?xml version="1.0" encoding="UTF-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="150dp"
        android:height="150dp"
        android:viewportHeight="24.0"
        android:viewportWidth="24.0" >

    <group
        android:name="groupHeart"
        android:pivotX="12"
        android:pivotY="12">

        <path
            android:name="heart"
            android:fillColor="#C2185B"
            android:pathData="M 12.0,21.35 l -1.45,-1.32 C 5.4,15.36,2.0,12.28,2.0,8.5 
            C 2.0,5.42,4.42,3.0,7.5,3.0 c 1.74,0.0,3.41,0.81,4.5,2.09 
            C 13.09,3.81,14.76,3.0,16.5,3.0 C 19.58,3.0,22.0,5.42,22.0,8.5 
            c 0.0,3.78,-3.4,6.86,-8.55,11.54 L 12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
            C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
            C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
            C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
            C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
            C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
            C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
            C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
            C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 L 12.0,21.35"/>
    </group>
</vector>

根節(jié)點是一個vector,里面是一個group包著一個path悄谐,和前面說的一樣介评,這個group不是必須的,往往是為了加載動畫而增加的爬舰。path是定義路徑们陆。

PS:這里有人可能會有疑問,這些“愛心”情屹、“Twitter”的path是怎么生成的呢坪仇?這里先提前簡單地解釋下:對于簡單的圖形,我們可以手動計算垃你,比如上面三條橫線變成箭頭的例子椅文,就是手動計算點坐標的。對于復雜的圖形惜颇,比如Twitter和愛心皆刺,手動計算不現(xiàn)實,我們可以找一些輔助軟件來生成凌摄。)

(4)兩個transition

<?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"
    android:drawable="@drawable/ic_heart">

    <target android:name="groupHeart">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:propertyName="rotation"
                android:valueFrom="-360"
                android:valueTo="0"
                android:duration="1000" />
        </aapt:attr>
    </target>

    <target android:name="heart">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:duration="1000"
                android:propertyName="pathData"
                android:valueFrom="M 12.0,21.35 l -1.45,-1.32 C 5.4,15.36,2.0,12.28,2.0,8.5 C 2.0,5.42,4.42,3.0,7.5,3.0 
                c 1.74,0.0,3.41,0.81,4.5,2.09 C 13.09,3.81,14.76,3.0,16.5,3.0 C 19.58,3.0,22.0,5.42,22.0,8.5 
                c 0.0,3.78,-3.4,6.86,-8.55,11.54 L 12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
                C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
                C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
                C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
                C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
                C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
                C 12.0,21.35,12.0,21.35,12.0,21.35 L 12.0,21.35"
                android:valueTo="M 22.46,6.0 l 0.0,0.0 C 21.69,6.35,20.86,6.58,20.0,6.69 C 20.88,6.16,21.56,5.32,21.88,4.31 
                c 0.0,0.0,0.0,0.0,0.0,0.0 C 21.05,4.81,20.13,5.16,19.16,5.36 C 18.37,4.5,17.26,4.0,16.0,4.0 
                c 0.0,0.0,0.0,0.0,0.0,0.0 L 16.0,4.0 C 13.65,4.0,11.73,5.92,11.73,8.29 C 11.73,8.63,11.77,8.96,11.84,9.27 
                C 8.28,9.09,5.11,7.38,3.0,4.79 C 2.63,5.42,2.42,6.16,2.42,6.94 C 2.42,8.43,3.17,9.75,4.33,10.5 
                C 3.62,10.5,2.96,10.3,2.38,10.0 C 2.38,10.0,2.38,10.0,2.38,10.03 C 2.38,12.11,3.86,13.85,5.82,14.24 
                C 5.46,14.34,5.08,14.39,4.69,14.39 C 4.42,14.39,4.15,14.36,3.89,14.31 C 4.43,16.0,6.0,17.26,7.89,17.29 
                C 6.43,18.45,4.58,19.13,2.56,19.13 C 2.22,19.13,1.88,19.11,1.54,19.07 C 3.44,20.29,5.7,21.0,8.12,21.0 
                C 16.0,21.0,20.33,14.46,20.33,8.79 C 20.33,8.6,20.33,8.42,20.32,8.23 C 21.16,7.63,21.88,6.87,22.46,6.0 L 22.46,6.0"
                android:valueType="pathType" />
        </aapt:attr>
    </target>
</animated-vector>
<?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"
    android:drawable="@drawable/ic_twitter">

    <target android:name="groupTwitter">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:propertyName="rotation"
                android:valueFrom="0"
                android:valueTo="-360"
                android:duration="1000" />
        </aapt:attr>
    </target>

    <target android:name="twitter">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:duration="1000"
                android:propertyName="pathData"
                android:valueFrom="M 22.46,6.0 l 0.0,0.0 C 21.69,6.35,20.86,6.58,20.0,6.69 C 20.88,6.16,21.56,5.32,21.88,4.31 
                c 0.0,0.0,0.0,0.0,0.0,0.0 C 21.05,4.81,20.13,5.16,19.16,5.36 C 18.37,4.5,17.26,4.0,16.0,4.0 
                c 0.0,0.0,0.0,0.0,0.0,0.0 L 16.0,4.0 C 13.65,4.0,11.73,5.92,11.73,8.29 C 11.73,8.63,11.77,8.96,11.84,9.27 
                C 8.28,9.09,5.11,7.38,3.0,4.79 C 2.63,5.42,2.42,6.16,2.42,6.94 C 2.42,8.43,3.17,9.75,4.33,10.5 
                C 3.62,10.5,2.96,10.3,2.38,10.0 C 2.38,10.0,2.38,10.0,2.38,10.03 C 2.38,12.11,3.86,13.85,5.82,14.24 
                C 5.46,14.34,5.08,14.39,4.69,14.39 C 4.42,14.39,4.15,14.36,3.89,14.31 C 4.43,16.0,6.0,17.26,7.89,17.29 
                C 6.43,18.45,4.58,19.13,2.56,19.13 C 2.22,19.13,1.88,19.11,1.54,19.07 C 3.44,20.29,5.7,21.0,8.12,21.0 
                C 16.0,21.0,20.33,14.46,20.33,8.79 C 20.33,8.6,20.33,8.42,20.32,8.23 C 21.16,7.63,21.88,6.87,22.46,6.0 L 22.46,6.0"
                android:valueTo="M 12.0,21.35 l -1.45,-1.32 C 5.4,15.36,2.0,12.28,2.0,8.5 C 2.0,5.42,4.42,3.0,7.5,3.0 
                c 1.74,0.0,3.41,0.81,4.5,2.09 C 13.09,3.81,14.76,3.0,16.5,3.0 C 19.58,3.0,22.0,5.42,22.0,8.5 
                c 0.0,3.78,-3.4,6.86,-8.55,11.54 L 12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
                C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
                C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
                C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
                C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
                C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 C 12.0,21.35,12.0,21.35,12.0,21.35 
                C 12.0,21.35,12.0,21.35,12.0,21.35 L 12.0,21.35"
                android:valueType="pathType"/>
        </aapt:attr>
    </target>
</animated-vector>

兩個transition分別定義了從 off 到 on 和從 on 到 off 時切換動畫羡蛾。

根節(jié)點是一個animated-vector,它有一個重要的屬性drawable锨亏,這個屬性指定動畫前的初始狀態(tài)痴怨,就是一個普通的vector。

下面兩個target是定義動畫器予,每一個target都有一個name屬性浪藻,指定動畫作用于哪個對象上,這個對象就是上面drawable里定義的名字乾翔。<aapt:attr>這一層就是固定寫法爱葵,我也不知道為什么要定義這一層~[/尷尬]。再下面就是ObjectAnmator末融,定義具體的動畫钧惧。通過propertyName來區(qū)分動畫類型暇韧,rotation是旋轉(zhuǎn)勾习,pathData是path轉(zhuǎn)換。旋轉(zhuǎn)動畫就不說了懈玻,path動畫轉(zhuǎn)換前面也分析過了巧婶。

OK乾颁,至此我們已經(jīng)把動畫都定義好了。因為比較復雜艺栈,我們再來捋一遍英岭。
(1)首先定義一個animated-selector,它定義兩個item湿右,對應(yīng)兩種狀態(tài)on诅妹、off的顯示,再定義兩個transition用于狀態(tài)變化時啟動動畫毅人。
(2)兩個item是vector類型吭狡,定義要顯示的path。
(3)兩個transition是animated-vector類型丈莺,定義從一個狀態(tài)到另一個狀態(tài)時的動畫划煮,在指定動畫時要注意,一個對象上只能加載一個動畫缔俄,如果動畫個數(shù)比對象個數(shù)多弛秋,要用group把對象包裹起來。

可是問題來了俐载,這樣只是定義好了動畫蟹略,但是還是動不起來啊。因為animated-selector怎么知道View的狀態(tài)變化了呢遏佣?所以還差最后一步科乎,把View的狀態(tài)和animated-selector關(guān)聯(lián)起來。

private boolean isTwitterChecked = false;
public void onTwitterClick(View view) {
        isTwitterChecked = !isTwitterChecked;
        final int[] stateSet = {android.R.attr.state_checked * (isTwitterChecked ? 1 : -1)};
        imageView.setImageState(stateSet, true);
    }

好啦贼急,這樣當我們點擊圖片時茅茂,通過調(diào)用imageView.setImageState就可以切換狀態(tài),從而切換 Twitter 和 heart 的顯示太抓。再來欣賞下動畫吧空闲。

PathMorphing

trimPath

trimPath也是一種動畫類型,它是通過對路徑的裁剪實現(xiàn)的動畫走敌。先看示例:

TrimPath

效果還是比較酷炫的碴倾,代碼實現(xiàn)和上面Twitter基本類似。直接貼代碼:
(1)animated-selector基本和上面類似掉丽,就不分析了

<?xml version="1.0" encoding="utf-8"?>
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@+id/state_on"
          android:drawable="@drawable/bar"
          android:state_checked="true"/>

    <item android:id="@+id/state_off"
          android:drawable="@drawable/search" />

    <transition
        android:fromId="@id/state_off"
        android:toId="@id/state_on"
        android:drawable="@drawable/avd_search_to_bar" />

    <transition
        android:fromId="@id/state_on"
        android:toId="@id/state_off"
        android:drawable="@drawable/avd_bar_to_search" />
</animated-selector>

(2)兩個item也基本類似跌榔,也不分析了

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="300dp"
        android:height="48dp"
        android:viewportWidth="150"
        android:viewportHeight="24">

    <path
        android:name="search"
        android:pathData="M141,17 A9,9 0 1,1 142,16 L149,22"
        android:strokeWidth="2"
        android:strokeColor="#f51035"
        android:strokeAlpha="0.8"
        android:strokeLineCap="round"
        android:trimPathStart="1"/>

    <path
        android:name="bar"
        android:pathData="M10,22 L149,22"
        android:strokeWidth="2"
        android:strokeColor="#f51035"
        android:strokeAlpha="0.8"
        android:strokeLineCap="round" />
</vector>
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="300dp"
        android:height="48dp"
        android:viewportWidth="150"
        android:viewportHeight="24">

    <path
        android:name="search"
        android:pathData="M141,17 A9,9 0 1,1 142,16 L149,22"
        android:strokeWidth="2"
        android:strokeColor="#f51035"
        android:strokeAlpha="0.8"
        android:strokeLineCap="round" />

    <path
        android:name="bar"
        android:pathData="M10,22 L149,22"
        android:strokeWidth="2"
        android:strokeColor="#f51035"
        android:strokeAlpha="0.8"
        android:strokeLineCap="round"
        android:trimPathStart="1"/>
</vector>

(3)兩個transition,這里和前面稍有不同捶障。我們拿最后一個分析下僧须。

<?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"
    android:drawable="@drawable/bar">

    <target android:name="search">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:propertyName="trimPathStart"
                android:valueFrom="1"
                android:valueTo="0"
                android:valueType="floatType"
                android:duration="1000"  />
        </aapt:attr>
    </target>

    <target android:name="bar">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:propertyName="trimPathStart"
                android:valueFrom="0"
                android:valueTo="1"
                android:valueType="floatType"
                android:duration="1000" />
        </aapt:attr>
    </target>
</animated-vector>
<?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"
    android:drawable="@drawable/search">

    <target android:name="search">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:propertyName="trimPathStart"
                android:valueFrom="0"
                android:valueTo="1"
                android:valueType="floatType"
                android:duration="1000"  />
        </aapt:attr>
    </target>

    <target android:name="bar">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:propertyName="trimPathStart"
                android:valueFrom="1"
                android:valueTo="0"
                android:valueType="floatType"
                android:duration="1000" />
        </aapt:attr>
    </target>
</animated-vector>

首先根節(jié)點是一個animated-vector,有一個drawable屬性项炼,下面包含兩個target子節(jié)點担平,整體結(jié)構(gòu)上沒有變化示绊。區(qū)別就在target中的ObjectAnimator。

propertyName是trimPathStart暂论,表示這是一個trimPath類型的動畫(還有trimPathEnd面褐,方向相反)。trimPath的原理是從一段path上裁剪出一小部分顯示取胎,通過改變裁剪的長度展哭,形成一個漸變的動畫。

上面的demo中闻蛀,其實是有兩段path摄杂,一段是放大鏡,一段是橫線循榆。就像這樣:

image

初始狀態(tài)析恢,橫線顯示的長度是0,所以我們只能看到一個放大鏡:

image

動畫開始后秧饮,放大鏡裁剪的部分逐漸變小映挂,橫線裁剪的部分逐漸變大,直至放大鏡消失盗尸,只剩橫線柑船。

image

trimPath動畫的寫法也基本是固定的

<objectAnimator
    android:propertyName="trimPathStart"
    android:valueFrom="1"
    android:valueTo="0"
    android:valueType="floatType"
    android:duration="1000" />

valueFrom和valueTo表示裁剪的起始點和結(jié)束點,valueType是float類型泼各,duration是1000毫秒鞍时。這樣就實現(xiàn)了放大鏡和橫線切換顯示的動畫啦。

總結(jié)

這一篇我們基本講完了Android中的矢量動畫扣蜻,這塊知識點都不難逆巍,就是太亂。我盡量把思路捋的順一點了莽使,用問題引出問題的方式把所有知識點串起來锐极,這樣更容易理清關(guān)系。如果完整看到這里的話你一定會發(fā)現(xiàn)還是有問題,Android系統(tǒng)提供的vector、animated-vector悠咱、animated-selector雖然很強大,但是有一個致命的缺點赌朋,就是只能在xml中寫死,不能通過java代碼動態(tài)構(gòu)建,并且我們不能控制動畫的過程。所以這又是個頭疼的問題汪榔。怎么辦呢,下一個靚仔在哪里罕拂?

下一篇

下一篇應(yīng)該是這個系列總結(jié)篇揍异,我們會在系統(tǒng)矢量動畫的基礎(chǔ)上封裝一些自己的庫全陨,實現(xiàn)一些額外的功能爆班。最后我們還會封裝一個通用動畫庫衷掷,簡化動畫的使用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末柿菩,一起剝皮案震驚了整個濱河市戚嗅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌枢舶,老刑警劉巖懦胞,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異凉泄,居然都是意外死亡躏尉,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門后众,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胀糜,“玉大人,你說我怎么就攤上這事蒂誉〗淘澹” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵右锨,是天一觀的道長括堤。 經(jīng)常有香客問我,道長绍移,這世上最難降的妖魔是什么悄窃? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮蹂窖,結(jié)果婚禮上广匙,老公的妹妹穿的比我還像新娘。我一直安慰自己恼策,他們只是感情好鸦致,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著涣楷,像睡著了一般分唾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上狮斗,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天绽乔,我揣著相機與錄音,去河邊找鬼碳褒。 笑死折砸,一個胖子當著我的面吹牛看疗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播睦授,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼两芳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了去枷?” 一聲冷哼從身側(cè)響起怖辆,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎删顶,沒想到半個月后竖螃,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡逗余,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年特咆,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片录粱。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡腻格,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出关摇,到底是詐尸還是另有隱情荒叶,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布输虱,位于F島的核電站些楣,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏宪睹。R本人自食惡果不足惜愁茁,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望亭病。 院中可真熱鬧鹅很,春花似錦、人聲如沸罪帖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽整袁。三九已至菠齿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間坐昙,已是汗流浹背绳匀。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人疾棵。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓戈钢,卻偏偏與公主長得像,于是被迫代替她去往敵國和親是尔。 傳聞我的和親對象是個殘疾皇子殉了,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

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

  • Android Vector曲折的兼容之路 兩年前寫書的時候,就在研究Android L提出的Vector嗜历,可研究...
    eclipse_xu閱讀 34,990評論 30 263
  • 目錄 Android高級動畫(1)http://www.reibang.com/p/48554844a2dbAnd...
    大公爵閱讀 9,201評論 20 55
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,163評論 25 707
  • 感恩一早同事幫我買好的物品宣渗! 感恩清潔工一早將樓道打掃的非常干凈抖所,讓我們有舒適的環(huán)境梨州! 感恩客戶的來電,對我充分的...
    我不叫許仲斌閱讀 261評論 0 3
  • [JVM] 雖然大部分情況下不需要我們直接對Java內(nèi)存方面進行直接操作田轧,但是了解其中的原理和調(diào)優(yōu)還是比較重要的暴匠,...
    ChaosCoffee閱讀 324評論 0 0