? ? ? 接著上篇Android中的動畫(XML方式)實(shí)踐(逐幀動畫與補(bǔ)間動畫)來學(xué)習(xí)下屬性動畫。
? ? 我們知道屬性動畫是API11(android3.0)新加入的特性。其實(shí)部分常用的動畫效果靠傳統(tǒng)動畫也可解決,那么:
為什么要引入屬性動畫
? ? ? 我們先看看傳統(tǒng)動畫能實(shí)現(xiàn)什么:幀動畫功能單一不必多說(圖片順序播放),再看補(bǔ)間動畫---可對View進(jìn)行一系列的效果變換(淡入淡出、縮放、平移、旋轉(zhuǎn))。看上句加粗部分便能明白,補(bǔ)間動畫有兩個(gè)局限性:1.作用對象單一(View)2.效果變換固定。舉幾個(gè)例子:1.我要給TextView加個(gè)動畫,從當(dāng)前寬度增加到300像素。這個(gè)用補(bǔ)間動畫是實(shí)現(xiàn)不了的,有人說可以通過x方向縮放實(shí)現(xiàn),但你要那么做了,就會把里面的文字也在x方向拉伸,而不僅僅改變textview寬度(改變了整個(gè)textview)。2.我要對一個(gè)imageview(想象一下:顯示一個(gè)大美女的那種)做個(gè)3D旋轉(zhuǎn),這個(gè)用補(bǔ)間動畫也是做不了的。還有一點(diǎn)可以說是補(bǔ)間動畫最坑的地方:它只改變View的顯示,而沒改變View的屬性。這就會造成類似下圖那種好玩(cao dan)的現(xiàn)象:

那屬性動畫就能實(shí)現(xiàn)這些補(bǔ)間動畫不能實(shí)現(xiàn)的效果嗎?是的!連帶也把補(bǔ)間動畫能實(shí)現(xiàn)的效果也給實(shí)現(xiàn)了。是不是很強(qiáng)勢。。。
開始使用屬性動畫
在開始使用之前,我們首先要知道它能用在哪?否則會鬧出類似拿剁骨刀削蘋果的笑話。
之所以稱之為屬性動畫,是因?yàn)樗梢詫θ我鈱ο蟮膶傩赃M(jìn)行動畫變換。也就是說:只要對象有這個(gè)屬性,你都能用屬性動畫來實(shí)現(xiàn)動畫(java中有萬物皆對象一說,可見屬性動畫的適用范圍之廣)。大致含義搞清楚了,下面就開始寫幾個(gè)例子,學(xué)習(xí)一下(以屬性動畫中常用的三個(gè)類:ObjectAnimator(繼承自ValueAnimator),ValueAnimator,AnimatorSet(動畫集合)為例):
1.以view自身中心為旋轉(zhuǎn)點(diǎn)順時(shí)針旋轉(zhuǎn)半圈(ObjectAnimator實(shí)現(xiàn)):

看看效果圖:

2.對view背景色(透明-橘色-亮綠)做改變(ValueAnimator實(shí)現(xiàn)):

效果圖:

3.對view同時(shí)做漸變,縮放,旋轉(zhuǎn)操作(AnimatorSet實(shí)現(xiàn)):

運(yùn)行效果:

上面分別使用ObjectAnimator,ValueAnimator和AnimatorSet實(shí)現(xiàn)了一些效果。那下面一個(gè)個(gè)依次的詳細(xì)說一下:
ObjectAnimator
第一個(gè)例子就足以證明一點(diǎn):用ObjectAnimator實(shí)現(xiàn)動畫真特么太簡單了,一行代碼就可以實(shí)現(xiàn)旋轉(zhuǎn)效果(當(dāng)然不只于旋轉(zhuǎn))。好吧,我們進(jìn)去ObjectAnimation類看看:

看看我們上面例子中用到了ofFloat方法,不禁要問:里面的設(shè)置的參數(shù)都是些什么鬼?現(xiàn)在就來找到那個(gè)方法,看看具體是怎么回事:

我們可以看到方法里面創(chuàng)建并了返回了一個(gè)ObjectAnimator對象。具體看一下各參數(shù)的含義吧:第一個(gè)參數(shù)target :表示要執(zhí)行動畫的對象;第二個(gè)參數(shù)propertyName:對象被改變屬性對應(yīng)的屬性名(這個(gè)后面還要詳細(xì)說);第三個(gè)可變參數(shù)values:可以理解為動畫過程設(shè)置的屬性值。
參數(shù)values展開來說:
當(dāng)我們調(diào)用方法指定values為一個(gè)值,表示動畫結(jié)束時(shí)屬性值(如上例);兩個(gè)值則表示開始值和結(jié)束值;三個(gè)或三個(gè)以上,其中第一個(gè)和最后一個(gè)值分別表示開始和結(jié)束屬性值,中間則表示動畫過程中任意屬性值。說得再多還不如試試更容易理解:values設(shè)為一個(gè)值的我們已經(jīng)試過,現(xiàn)在來試試設(shè)置多個(gè)值的:


其實(shí)ObjectAnimator類似ofFloat的方法還有ofInt,ofArgb,乃至ofObject等,這些方法都是設(shè)置動畫作用的對象、改變的屬性和動畫開始,結(jié)束還有中間(任意個(gè)數(shù))的屬性值。
參數(shù)propertyName屬性名詳解:
還拿ofFloat方法來說,第一個(gè)參數(shù)target 含義好理解,第三個(gè)參數(shù)values也說過了,那第二個(gè)參數(shù)propertyName到底怎么理解,是隨便寫一個(gè)字符串就行了嗎?顯然不是!上面ofFloat函數(shù)的注釋已經(jīng)做了解釋:第一個(gè)參數(shù)target對象應(yīng)該有個(gè)類似方法名為setName作用域?yàn)閜ublic的方法,第二個(gè)參數(shù)propertyName即可指定對應(yīng)屬性名為name。
就拿我們上面旋轉(zhuǎn)來說:... .ofFloat(mImageView,"rotation",...)? ? 我們指定屬性名為“rotation”,那肯定ImageView或其父類存在 setRotation 方法--果不其然在ImageView 父類View中找到了該方法:

然后還會發(fā)現(xiàn)一個(gè)好玩的現(xiàn)象--我們試著換種寫法:

把ofFloat換成ofInt,后面參數(shù)改為int型,發(fā)現(xiàn)會報(bào)錯(cuò)。大概可以理解為沒在ImageView(或其父類)中找到setter方法public void setRotation(int arg);我們從源碼中看到setRotation方法參數(shù)是float類型的,所以用ofFloat方法,它不會報(bào)錯(cuò),因?yàn)槟苷业较鄳?yīng)類型參數(shù)的setter方法。也就是說:方法ofXxx中的類型Xxx應(yīng)該與指定屬性對應(yīng)setter方法的參數(shù)值一致。這樣一說,我們我就會理解為什么可變參數(shù)values是指定屬性值的。
當(dāng)然也并不是只要作用對象target有setXxx方法,我們對target屬性xxx做動畫,就能生效:這里需要滿足兩個(gè)條件:
1.如果動畫沒有傳遞初始值,那么target中需要提供getXxx方法,因?yàn)橄到y(tǒng)要自己去取屬性的初始值,若不滿足這點(diǎn),程序會崩潰。比如:

由于ImageView中沒有g(shù)etImageResource方法但存在setImageResource,如上圖代碼段,沒指定初始值,這樣的話,運(yùn)行就會直接crash掉。
2.target對象的setXxx對屬性xxx所做的改變得通過一些途徑反映出來。就比如帶來UI上的改變。這很好理解,要不能在UI上給用戶反映出來,那用戶就沒法看到動畫效果??纯催@句:

imageview有setMaxWidth和getMaxWidth方法,但maxwidth屬性對imageview在外在表現(xiàn)上沒有影響的,所以我們看不到有任何效果。
對第一點(diǎn)還需要多說一下,不能錯(cuò)誤理解為target沒有g(shù)etXxx方法,運(yùn)行代碼就會崩潰,是有兩個(gè)條件(target沒有提供getXxx方法+沒有設(shè)置初始值)看看下面的代碼就可以明白了(同樣針對imageResourse):

運(yùn)行一下,是不會報(bào)錯(cuò)的:

PropertyValuesHolder
我們能不能僅僅使用一個(gè)動畫(ObjectAnimator)就實(shí)現(xiàn)多個(gè)效果呢?比如說旋轉(zhuǎn),縮放,漸變,位移幾個(gè)效果一起?(盡管這種“多效果”用AnimatorSet可輕松實(shí)現(xiàn))。
問題先留在這里,待會再解答。
上面有提到過ObjectAnimator類似ofFloat的方法還有ofInt,ofArgb,ofObject等,還有一個(gè)方法叫做ofPropertyValuesHolder:

函數(shù)返回值與ofFloat等一致為ObjectAnimator對象,參數(shù)target為動畫作用對象,那后面的values參數(shù):PropertyValuesHolder類型的可變數(shù)組是什么意思。這個(gè)PropertyValuesHolder是什么東西,看看該類:

還是看注釋:注釋第一句 看類名(Property-Values-Holder)其實(shí)就可以理解;第二句剛好可以回答上面提出帶答的問題。所以答案顯而易見--能。那就實(shí)現(xiàn)一個(gè)看看吧:


另:PropertyValuesHolder常用創(chuàng)建實(shí)例的函數(shù)有下面四種:
public static PropertyValuesHolder ofFloat(String propertyName, float... values)
public static PropertyValuesHolder ofInt(String propertyName, int... values)
public static PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator,Object... values)
public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values)
現(xiàn)在這里就不展開來說了。
未完下次再續(xù)。。。
由于作者水平有限,有紕漏或錯(cuò)誤處還望大家批評指正,謝謝!
感謝:
任玉剛 《Android開發(fā)藝術(shù)探索》