1 背景
不能只分析源碼呀恬叹,分析的同時也要整理歸納基礎(chǔ)知識,剛好有人微博私信讓全面說說Android的動畫同眯,所以今天來一發(fā)Android應(yīng)用的各種Animation大集合绽昼。英文厲害的請直接移步參考Android Developer。
Android系統(tǒng)提供了很多豐富的API去實現(xiàn)UI的2D與3D動畫须蜗,最主要的劃分可以分為如下幾類:
View Animation: 視圖動畫在古老的Android版本系統(tǒng)中就已經(jīng)提供了硅确,只能被用來設(shè)置View的動畫。
Drawable Animation: 這種動畫(也叫Frame動畫明肮、幀動畫)其實可以劃分到視圖動畫的類別菱农,專門用來一個一個的顯示Drawable的resources,就像放幻燈片一樣柿估。
Property Animation: 屬性動畫只對Android 3.0(API 11)以上版本的Android系統(tǒng)才有效循未,這種動畫可以設(shè)置給任何Object,包括那些還沒有渲染到屏幕上的對象秫舌。這種動畫是可擴展的的妖,可以讓你自定義任何類型和屬性的動畫。
可以看見足陨,當(dāng)前應(yīng)用程序開發(fā)涉及的主要動畫也就這三大類嫂粟,我們接下來以類別為基礎(chǔ)來慢慢展開說明。
2 View Animation(視圖動畫)使用詳解
2-1 視圖動畫概述
視圖動畫墨缘,也叫Tween(補間)動畫可以在一個視圖容器內(nèi)執(zhí)行一系列簡單變換(位置星虹、大小零抬、旋轉(zhuǎn)、透明度)搁凸。譬如媚值,如果你有一個TextView對象,您可以移動护糖、旋轉(zhuǎn)、縮放嚼松、透明度設(shè)置其文本嫡良,當(dāng)然,如果它有一個背景圖像献酗,背景圖像會隨著文本變化寝受。
補間動畫通過XML或Android代碼定義,建議使用XML文件定義罕偎,因為它更具可讀性很澄、可重用性。
如下是視圖動畫相關(guān)的類繼承關(guān)系:
java類名 | xml關(guān)鍵字 | 描述信息 |
---|---|---|
AlphaAnimation |
<alpha> 放置在res/anim/目錄下 |
漸變透明度動畫效果 |
RotateAnimation |
<rotate> 放置在res/anim/目錄下 |
畫面轉(zhuǎn)移旋轉(zhuǎn)動畫效果 |
ScaleAnimation |
<scale> 放置在res/anim/目錄下 |
漸變尺寸伸縮動畫效果 |
TranslateAnimation |
<translate> 放置在res/anim/目錄下 |
畫面轉(zhuǎn)換位置移動動畫效果 |
AnimationSet |
<set> 放置在res/anim/目錄下 |
一個持有其它動畫元素alpha颜及、scale甩苛、translate、rotate或者其它set元素的容器 |
通過上圖和上表可以直觀的看出來補間動畫的關(guān)系及種類了吧俏站,接下來我們就詳細(xì)一個一個的介紹一下各種補間動畫讯蒲。
2-2 視圖動畫詳細(xì)說明
可以看出來Animation抽象類是所有補間動畫類的基類,所以基類會提供一些通用的動畫屬性方法肄扎,如下我們就來詳細(xì)看看這些屬性墨林,關(guān)于這些屬性詳細(xì)官方解釋FQ點擊我或者FQ點擊我。
2-2-1 Animation屬性詳解
xml屬性 | java方法 | 解釋 |
---|---|---|
android:detachWallpaper | setDetachWallpaper(boolean) | 是否在壁紙上運行 |
android:duration | setDuration(long) | 動畫持續(xù)時間犯祠,毫秒為單位 |
android:fillAfter | setFillAfter(boolean) | 控件動畫結(jié)束時是否保持動畫最后的狀態(tài) |
android:fillBefore | setFillBefore(boolean) | 控件動畫結(jié)束時是否還原到開始動畫前的狀態(tài) |
android:fillEnabled | setFillEnabled(boolean) | 與android:fillBefore效果相同 |
android:interpolator | setInterpolator(Interpolator) | 設(shè)定插值器(指定的動畫效果旭等,譬如回彈等) |
android:repeatCount | setRepeatCount(int) | 重復(fù)次數(shù) |
android:repeatMode | setRepeatMode(int) | 重復(fù)類型有兩個值,reverse表示倒序回放衡载,restart表示從頭播放 |
android:startOffset | setStartOffset(long) | 調(diào)用start函數(shù)之后等待開始運行的時間搔耕,單位為毫秒 |
android:zAdjustment | setZAdjustment(int) | 表示被設(shè)置動畫的內(nèi)容運行時在Z軸上的位置(top/bottom/normal),默認(rèn)為normal |
也就是說月劈,無論我們補間動畫的哪一種都已經(jīng)具備了這種屬性度迂,也都可以設(shè)置使用這些屬性中的一個或多個。
那接下來我們就看看每種補間動畫特有的一些屬性說明吧猜揪。
2-2-2 Alpha屬性詳解
xml屬性 | java方法 | 解釋 |
---|---|---|
android:fromAlpha | AlphaAnimation(float fromAlpha, …) | 動畫開始的透明度(0.0到1.0惭墓,0.0是全透明,1.0是不透明) |
android:toAlpha | AlphaAnimation(…, float toAlpha) | 動畫結(jié)束的透明度而姐,同上 |
2-2-3 Rotate屬性詳解
xml屬性 | java方法 | 解釋 |
---|---|---|
android:fromDegrees | RotateAnimation(float fromDegrees, …) | 旋轉(zhuǎn)開始角度腊凶,正代表順時針度數(shù),負(fù)代表逆時針度數(shù) |
android:toDegrees | RotateAnimation(…, float toDegrees, …) | 旋轉(zhuǎn)結(jié)束角度,正代表順時針度數(shù)钧萍,負(fù)代表逆時針度數(shù) |
android:pivotX | RotateAnimation(…, float pivotX, …) | 縮放起點X坐標(biāo)(數(shù)值褐缠、百分?jǐn)?shù)、百分?jǐn)?shù)p风瘦,譬如50表示以當(dāng)前View左上角坐標(biāo)加50px為初始點队魏、50%表示以當(dāng)前View的左上角加上當(dāng)前View寬高的50%做為初始點、50%p表示以當(dāng)前View的左上角加上父控件寬高的50%做為初始點) |
android:pivotY | RotateAnimation(…, float pivotY) | 縮放起點Y坐標(biāo)万搔,同上規(guī)律 |
2-2-4 Scale屬性詳解
xml屬性 | java方法 | 解釋 |
---|---|---|
android:fromXScale | ScaleAnimation(float fromX, …) | 初始X軸縮放比例胡桨,1.0表示無變化 |
android:toXScale | ScaleAnimation(…, float toX, …) | 結(jié)束X軸縮放比例 |
android:fromYScale | ScaleAnimation(…, float fromY, …) | 初始Y軸縮放比例 |
android:toYScale | ScaleAnimation(…, float toY, …) | 結(jié)束Y軸縮放比例 |
android:pivotX | ScaleAnimation(…, float pivotX, …) | 縮放起點X軸坐標(biāo)(數(shù)值、百分?jǐn)?shù)瞬雹、百分?jǐn)?shù)p昧谊,譬如50表示以當(dāng)前View左上角坐標(biāo)加50px為初始點、50%表示以當(dāng)前View的左上角加上當(dāng)前View寬高的50%做為初始點酗捌、50%p表示以當(dāng)前View的左上角加上父控件寬高的50%做為初始點) |
android:pivotY | ScaleAnimation(…, float pivotY) | 縮放起點Y軸坐標(biāo)呢诬,同上規(guī)律 |
2-2-5 Translate屬性詳解
xml屬性 | java方法 | 解釋 |
---|---|---|
android:fromXDelta | TranslateAnimation(float fromXDelta, …) | 起始點X軸坐標(biāo)(數(shù)值、百分?jǐn)?shù)胖缤、百分?jǐn)?shù)p尚镰,譬如50表示以當(dāng)前View左上角坐標(biāo)加50px為初始點、50%表示以當(dāng)前View的左上角加上當(dāng)前View寬高的50%做為初始點草姻、50%p表示以當(dāng)前View的左上角加上父控件寬高的50%做為初始點) |
android:fromYDelta | TranslateAnimation(…, float fromYDelta, …) | 起始點Y軸從標(biāo)钓猬,同上規(guī)律 |
android:toXDelta | TranslateAnimation(…, float toXDelta, …) | 結(jié)束點X軸坐標(biāo),同上規(guī)律 |
android:toYDelta | TranslateAnimation(…, float toYDelta) | 結(jié)束點Y軸坐標(biāo)撩独,同上規(guī)律 |
2-2-6 AnimationSet詳解
AnimationSet繼承自Animation敞曹,是上面四種的組合容器管理類,沒有自己特有的屬性综膀,他的屬性繼承自Animation澳迫,所以特別注意,當(dāng)我們對set標(biāo)簽使用Animation的屬性時會對該標(biāo)簽下的所有子控件都產(chǎn)生影響剧劝。
2-3 視圖動畫使用方法
通過上面對于動畫的屬性介紹之后我們來看看在Android中這些動畫如何使用(PS:這里直接演示xml方式橄登,至于Java方式太簡單了就不說了),如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@[package:]anim/interpolator_resource"
android:shareInterpolator=["true" | "false"] >
<alpha
android:fromAlpha="float"
android:toAlpha="float" />
<scale
android:fromXScale="float"
android:toXScale="float"
android:fromYScale="float"
android:toYScale="float"
android:pivotX="float"
android:pivotY="float" />
<translate
android:fromXDelta="float"
android:toXDelta="float"
android:fromYDelta="float"
android:toYDelta="float" />
<rotate
android:fromDegrees="float"
android:toDegrees="float"
android:pivotX="float"
android:pivotY="float" />
<set>
...
</set>
</set>
ImageView spaceshipImage = (ImageView) findViewById(R.id.spaceshipImage);
Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);
spaceshipImage.startAnimation(hyperspaceJumpAnimation);
上面就是一個標(biāo)準(zhǔn)的使用我們定義的補間動畫的模板讥此。至于補間動畫的使用拢锹,Animation還有如下一些比較實用的方法介紹:
Animation類的方法 | 解釋 |
---|---|
reset() | 重置Animation的初始化 |
cancel() | 取消Animation動畫 |
start() | 開始Animation動畫 |
setAnimationListener(AnimationListener listener) | 給當(dāng)前Animation設(shè)置動畫監(jiān)聽 |
hasStarted() | 判斷當(dāng)前Animation是否開始 |
hasEnded() | 判斷當(dāng)前Animation是否結(jié)束 |
既然補間動畫只能給View使用,那就來看看View中和動畫相關(guān)的幾個常用方法吧萄喳,如下:
View類的常用動畫操作方法 | 解釋 |
---|---|
startAnimation(Animation animation) | 對當(dāng)前View開始設(shè)置的Animation動畫 |
clearAnimation() | 取消當(dāng)View在執(zhí)行的Animation動畫 |
到此整個Android的補間動畫常用詳細(xì)屬性及方法全部介紹完畢卒稳,如有特殊的屬性需求可以訪問Android Developer查閱即可。如下我們就來個綜合大演練他巨。
2-4 視圖動畫注意事項
關(guān)于視圖動畫(補間動畫)的例子我就不介紹了充坑,網(wǎng)上簡直多的都泛濫了减江。只是強調(diào)在使用補間動畫時注意如下一點即可:
特別特別注意:補間動畫執(zhí)行之后并未改變View的真實布局屬性值。切記這一點捻爷,譬如我們在Activity中有一個 Button在屏幕上方辈灼,我們設(shè)置了平移動畫移動到屏幕下方然后保持動畫最后執(zhí)行狀態(tài)呆在屏幕下方,這時如果點擊屏幕下方動畫執(zhí)行之后的Button是沒 有任何反應(yīng)的也榄,而點擊原來屏幕上方?jīng)]有Button的地方卻響應(yīng)的是點擊Button的事件巡莹。
2-5 視圖動畫Interpolator插值器詳解
2-5-1 插值器簡介
介紹補間動畫插值器之前我們先來看一幅圖,如下:
可以看見其實各種插值器都是實現(xiàn)了Interpolator接口而已手蝎,同時可以看見系統(tǒng)提供了許多已經(jīng)實現(xiàn)OK的插值器榕莺,具體如下:
java類 | xml id值 | 描述 |
---|---|---|
AccelerateDecelerateInterpolator | @android:anim/accelerate_decelerate_interpolator | 動畫始末速率較慢,中間加速 |
AccelerateInterpolator | @android:anim/accelerate_interpolator | 動畫開始速率較慢棵介,之后慢慢加速 |
AnticipateInterpolator | @android:anim/anticipate_interpolator | 開始的時候從后向前甩 |
AnticipateOvershootInterpolator | @android:anim/anticipate_overshoot_interpolator | 類似上面AnticipateInterpolator |
BounceInterpolator | @android:anim/bounce_interpolator | 動畫結(jié)束時彈起 |
CycleInterpolator | @android:anim/cycle_interpolator | 循環(huán)播放速率改變?yōu)檎仪€ |
DecelerateInterpolator | @android:anim/decelerate_interpolator | 動畫開始快然后慢 |
LinearInterpolator | @android:anim/linear_interpolator | 動畫勻速改變 |
OvershootInterpolator | @android:anim/overshoot_interpolator | 向前彈出一定值之后回到原來位置 |
PathInterpolator | 新增,定義路徑坐標(biāo)后按照路徑坐標(biāo)來跑吧史。 |
如上就是系統(tǒng)提供的一些插值器邮辽,下面我們來看看怎么使用他們。
2-5-2 插值器使用方法
插值器的使用比較簡答贸营,如下:
<set android:interpolator="@android:anim/accelerate_interpolator">
...
</set>
2-5-3 插值器的自定義
有時候你會發(fā)現(xiàn)系統(tǒng)提供的插值器不夠用吨述,可能就像View一樣需要自定義。所以接下來我們來看看插值器的自定義钞脂,關(guān)于插值器的自定義分為兩種實現(xiàn)方式揣云,xml自定義實現(xiàn)(其實就是對現(xiàn)有的插值器的一些屬性修改)或者java代碼實現(xiàn)方式。如下我們來說說冰啃。
先看看XML自定義插值器的步驟:
- 在res/anim/目錄下創(chuàng)建filename.xml文件邓夕。
- 修改你準(zhǔn)備自定義的插值器如下:
<?xml version="1.0" encoding="utf-8"?>
<InterpolatorName xmlns:android="http://schemas.android.com/apk/res/android"
android:attribute_name="value"
/>
- 在你的補間動畫文件中引用該文件即可。
可以看見上面第二步修改的是現(xiàn)有插值器的一些屬性阎毅,但是有些插值器卻不具備修改屬性焚刚,具體如下:
<accelerateDecelerateInterpolator>
無可自定義的attribute。
<accelerateInterpolator>
android:factor 浮點值扇调,加速速率(默認(rèn)值為1)矿咕。
<anticipateInterploator>
android:tension 浮點值,起始點后拉的張力數(shù)(默認(rèn)值為2)狼钮。
<anticipateOvershootInterpolator>
android:tension 浮點值碳柱,起始點后拉的張力數(shù)(默認(rèn)值為2)。
android:extraTension 浮點值熬芜,拉力的倍數(shù)(默認(rèn)值為1.5)莲镣。
<bounceInterpolator>
無可自定義的attribute。
<cycleInterplolator>
android:cycles 整形猛蔽,循環(huán)的個數(shù)(默認(rèn)為1)剥悟。
<decelerateInterpolator>
android:factor 浮點值灵寺,減速的速率(默認(rèn)為1)。
<linearInterpolator>
無可自定義的attribute区岗。
<overshootInterpolator>
android:tension 浮點值略板,超出終點后的張力(默認(rèn)為2)。
再來看看Java自定義插值器的(Java自定義插值器其實是xml自定義的升級慈缔,也就是說如果我們修改xml的屬性還不能滿足需求叮称,那就可以選擇通過Java來實現(xiàn))方式。
可以看見上面所有的Interpolator都實現(xiàn)了Interpolator接口藐鹤,而Interpolator接口又繼承自 TimeInterpolator瓤檐,TimeInterpolator接口定義了一個float getInterpolation(float input);方法,這個方法是由系統(tǒng)調(diào)用的娱节,其中的參數(shù)input代表動畫的時間挠蛉,在0和1之間,也就是開始和結(jié)束之間肄满。
如下就是一個動畫始末速率較慢谴古、中間加速的AccelerateDecelerateInterpolator插值器:
public class AccelerateDecelerateInterpolator extends BaseInterpolator
implements NativeInterpolatorFactory {
......
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
......
}
到此整個補間動畫與補間動畫的插值器都分析完畢了,接下來看下別的動畫稠歉。
3 Drawable Animation(Drawable動畫)使用詳解
3-1 Drawable動畫概述
Drawable動畫其實就是Frame動畫(幀動畫)掰担,它允許你實現(xiàn)像播放幻燈片一樣的效果,這種動畫的實質(zhì)其實是Drawable怒炸,所以這種動畫的XML定義方式文件一般放在res/drawable/目錄下带饱。具體關(guān)于幀動畫的xml使用方式FQ點擊我查看,java方式FQ點擊我查看阅羹。
如下圖就是幀動畫的源碼文件:
可以看見實際的真實父類就是Drawable勺疼。
3-2 Drawable動畫詳細(xì)說明
我們依舊可以使用xml或者java方式實現(xiàn)幀動畫。但是依舊推薦使用xml灯蝴,具體如下:
<animation-list>
必須是根節(jié)點斗搞,包含一個或者多個<item>
元素玖瘸,屬性有:
- android:oneshot true代表只執(zhí)行一次,false循環(huán)執(zhí)行。
-
<item>
類似一幀的動畫資源呀闻。
<item>
animation-list的子項躺翻,包含屬性如下:
- android:drawable 一個frame的Drawable資源鸠项。
- android:duration 一個frame顯示多長時間饼暑。
3-3 Drawable動畫實例演示
關(guān)于幀動畫相對來說比較簡單,這里給出一個常規(guī)使用框架狡忙,如下:
<!-- 注意:rocket.xml文件位于res/drawable/目錄下 -->
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot=["true" | "false"] >
<item
android:drawable="@[package:]drawable/drawable_resource_name"
android:duration="integer" />
</animation-list>
ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
rocketImage.setBackgroundResource(R.drawable.rocket_thrust);
rocketAnimation = (AnimationDrawable) rocketImage.getBackground();
rocketAnimation.start();
特別注意梳虽,AnimationDrawable的start()方法不能在Activity的onCreate方法中調(diào)運,因為AnimationDrawable還未完全附著到window上灾茁,所以最好的調(diào)運時機是onWindowFocusChanged()方法中窜觉。
至此幀動畫也就說明完成了谷炸。讓我們接下來進入Android更牛叉的動畫類型。
4 Property Animation(屬性動畫)使用詳解
在使用屬性動畫之前先來看幾個常用的View屬性成員:
- translationX禀挫,translationY:控制View的位置旬陡,值是相對于View容器左上角坐標(biāo)的偏移。
- rotationX语婴,rotationY:控制相對于軸心旋轉(zhuǎn)描孟。
- x,y:控制View在容器中的位置砰左,即左上角坐標(biāo)加上translationX和translationY的值匿醒。
- alpha:控制View對象的alpha透明度值。
這幾個常用的屬性相信大家都很熟悉缠导,接下來的屬性動畫我們就從這里展開廉羔。
4-1 屬性動畫概述
Android 3.0以后引入了屬性動畫,屬性動畫可以輕而易舉的實現(xiàn)許多View動畫做不到的事僻造,上面也看見了蜜另,View動畫無非也就做那幾種事情,別的也搞不定嫡意,而 屬性動畫就可以的,譬如3D旋轉(zhuǎn)一張圖片捣辆。其實說白了蔬螟,你記住一點就行,屬性動畫實現(xiàn)原理就是修改控件的屬性值實現(xiàn)的動畫汽畴。
具體先看下類關(guān)系:
/**
* This is the superclass for classes which provide basic support for animations which can be
* started, ended, and have <code>AnimatorListeners</code> added to them.
*/
public abstract class Animator implements Cloneable {
......
}
所有的屬性動畫的抽象基類就是他旧巾。我們看下他的實現(xiàn)子類:
其實可以看見,屬性動畫的實現(xiàn)有7個類(PS忍些,之所以類繼承關(guān)系列表會出來那么多是因為我下載了所有版本的SDK鲁猩,你只用關(guān)注我紅點標(biāo)注的就行,妹 的罢坝,ubuntu下圖片處理工具怎么都這么難用)廓握,進去粗略分析可以發(fā)現(xiàn),好幾個是hide的類嘁酿,而其他可用的類繼承關(guān)系又如下:
java類名 | xml關(guān)鍵字 | 描述信息 |
---|---|---|
ValueAnimator |
<animator> 放置在res/animator/目錄下 |
在一個特定的時間里執(zhí)行一個動畫 |
TimeAnimator | 不支持/點我查看原因 | 時序監(jiān)聽回調(diào)工具 |
ObjectAnimator |
<objectAnimator> 放置在res/animator/目錄下 |
一個對象的一個屬性動畫 |
AnimatorSet |
<set> 放置在res/animator/目錄下 |
動畫集合 |
所以可以看見隙券,我們平時使用屬性動畫的重點就在于AnimatorSet、ObjectAnimator闹司、TimeAnimator娱仔、ValueAnimator。所以接下來我們就來依次說說如何使用游桩。
4-2 屬性動畫詳細(xì)說明
4-2-1 屬性動畫計算原理
Android屬性動畫(注意最低兼容版本,不過可以使用開源項目來替代低版本問題)提供了以下屬性:
- Duration:動畫的持續(xù)時間盹憎;
- TimeInterpolation:定義動畫變化速率的接口筛峭,所有插值器都必須實現(xiàn)此接口,如線性脚乡、非線性插值器蜒滩;
- TypeEvaluator:用于定義屬性值計算方式的接口,有int奶稠、float俯艰、color類型,根據(jù)屬性的起始锌订、結(jié)束值和插值一起計算出當(dāng)前時間的屬性值竹握;
- Animation sets:動畫集合,即可以同時對一個對象應(yīng)用多個動畫辆飘,這些動畫可以同時播放也可以對不同動畫設(shè)置不同的延遲啦辐;
- Frame refreash delay:多少時間刷新一次,即每隔多少時間計算一次屬性值蜈项,默認(rèn)為10ms芹关,最終刷新時間還受系統(tǒng)進程調(diào)度與硬件的影響;
- Repeat Country and behavoir:重復(fù)次數(shù)與方式紧卒,如播放3次侥衬、5次、無限循環(huán)跑芳,可以讓此動畫一直重復(fù)轴总,或播放完時向反向播放;
接下來先來看官方為了解釋原理給出的兩幅圖(其實就是初中物理題博个,不解釋):
上面就是一個線性勻速動畫怀樟,描述了一個Object的X屬性運動動畫,該對象的X坐標(biāo)在40ms內(nèi)從0移動到40盆佣,每10ms刷新一次往堡,移動4次,每次移動為40/4=10pixel罪塔。
上面是一個非勻速動畫投蝉,描述了一個Object的X屬性運動動畫,該對象的X坐標(biāo)在40ms內(nèi)從0移動到40征堪,每10ms刷新一次瘩缆,移動4次,但是速率不同佃蚜,開始和結(jié)束的速度要比中間部分慢庸娱,即先加速后減速着绊。
接下來我們來詳細(xì)的看一下,屬性動畫系統(tǒng)的重要組成部分是如何計算動畫值的熟尉,下圖描述了如上面所示動畫的實現(xiàn)作用過程归露。
其中的ValueAnimator是動畫的執(zhí)行類,跟蹤了當(dāng)前動畫的執(zhí)行時間和當(dāng)前時間下的屬性值斤儿;ValueAnimator封裝了動畫的 TimeInterpolator時間插值器和一個TypeEvaluator類型估值剧包,用于設(shè)置動畫屬性的值,就像上面圖2非線性動畫 里往果,TimeInterpolator使用了AccelerateDecelerateInterpolator疆液、TypeEvaluator使用了 IntEvaluator。
為了執(zhí)行一個動畫陕贮,你需要創(chuàng)建一個ValueAnimator堕油,并且指定目標(biāo)對象屬性的開始、結(jié)束值和持續(xù)時間肮之。在調(diào)用start后掉缺,整個動畫過程 中, ValueAnimator會根據(jù)已經(jīng)完成的動畫時間計算得到一個0到1之間的分?jǐn)?shù)戈擒,代表該動畫的已完成動畫百分比眶明。0表示0%,1表示100%筐高,譬如上 面圖一線性勻速動畫中總時間 t = 40 ms赘来,t = 10 ms的時候是 0.25。
當(dāng)ValueAnimator計算完已完成動畫分?jǐn)?shù)后凯傲,它會調(diào)用當(dāng)前設(shè)置的TimeInterpolator,去計算得到一個 interpolated(插值)分?jǐn)?shù)嗦篱,在計算過程中冰单,已完成動畫百分比會被加入到新的插值計算中。如上圖2非線性動畫中灸促,因為動畫的運動是緩慢加速的诫欠, 它的插值分?jǐn)?shù)大約是 0.15,小于t = 10ms時的已完成動畫分?jǐn)?shù)0.25浴栽。而在上圖1中荒叼,這個插值分?jǐn)?shù)一直和已完成動畫分?jǐn)?shù)是相同的。
當(dāng)插值分?jǐn)?shù)計算完成后典鸡,ValueAnimator會根據(jù)插值分?jǐn)?shù)調(diào)用合適的 TypeEvaluator去計算運動中的屬性值被廓。
好了,現(xiàn)在我們來看下代碼就明白這段話了萝玷,上面圖2非線性動畫里嫁乘,TimeInterpolator使用了 AccelerateDecelerateInterpolator昆婿、TypeEvaluator使用了IntEvaluator。所以這些類都是標(biāo)準(zhǔn)的 API蜓斧,我們來看下標(biāo)準(zhǔn)API就能類比自己寫了仓蛆,如下:
首先計算已完成動畫時間分?jǐn)?shù)(以10ms為例):t=10ms/40ms=0.25。
接著看如下源碼如何實現(xiàn)計算差值分?jǐn)?shù)的:
public class AccelerateDecelerateInterpolator extends BaseInterpolator
implements NativeInterpolatorFactory {
public AccelerateDecelerateInterpolator() {
}
......
//這是我們關(guān)注重點挎春,可以發(fā)現(xiàn)如下計算公式計算后(input即為時間因子)插值大約為0.15看疙。
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
......
}
其實AccelerateDecelerateInterpolator的基類接口就是TimeInterpolator,如下直奋,他只有g(shù)etInterpolation方法能庆,也就是上面我們關(guān)注的方法。
public interface TimeInterpolator {
float getInterpolation(float input);
}
接著ValueAnimator會根據(jù)插值分?jǐn)?shù)調(diào)用合適的TypeEvaluator(IntEvaluator)去計算運動中的屬性值帮碰,如下相味,因為startValue = 0,所以屬性值:0+0.15*(40-0)= 6殉挽。
public class IntEvaluator implements TypeEvaluator<Integer> {
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
}
這就是官方給的一個關(guān)于屬性動畫實現(xiàn)的過程及基本原理解釋丰涉,相信你看到這里是會有些迷糊的,沒關(guān)系斯碌,你先有個大致概念就行一死,接下來我們會慢慢進入實戰(zhàn),因為Android的屬性動畫相對于其他動畫來說涉及的知識點本來就比較復(fù)雜傻唾,所以我們慢慢來投慈。
4-2-2 XML方式屬性動畫
在xml中可直接用的屬性動畫節(jié)點有ValueAnimator、ObjectAnimator冠骄、AnimatorSet伪煤。如下是官方的一個例子和解釋(詳情點我):
<set
android:ordering=["together" | "sequentially"]>
<objectAnimator
android:propertyName="string"
android:duration="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]/>
<animator
android:duration="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]/>
<set>
...
</set>
</set>
<set>
屬性解釋:
xml屬性 | 解釋 |
---|---|
android:ordering | 控制子動畫啟動方式是先后有序的還是同時進行。sequentially:動畫按照先后順序凛辣;together(默認(rèn)):動畫同時啟動抱既; |
<objectAnimator>
屬性解釋:
xml屬性 | 解釋 |
---|---|
android:propertyName | String類型,必須要設(shè)置的節(jié)點屬性扁誓,代表要執(zhí)行動畫的屬性(通過名字引用)防泵,辟如你可以指定了一個View的”alpha” 或者 “backgroundColor” ,這個objectAnimator元素沒有對外說明target屬性蝗敢,所以你不能在XML中設(shè)置執(zhí)行這個動畫捷泞,必須通過調(diào)用 loadAnimator()方法加載你的XML動畫資源,然后調(diào)用setTarget()應(yīng)用到具備這個屬性的目標(biāo)對象上(譬如TextView)寿谴。 |
android:valueTo | float锁右、int或者color類型,必須要設(shè)置的節(jié)點屬性,表明動畫結(jié)束的點骡湖;如果是顏色的話贱纠,由6位十六進制的數(shù)字表示。 |
android:valueFrom | 相對應(yīng)valueTo响蕴,動畫的起始點谆焊,如果沒有指定,系統(tǒng)會通過屬性的get方法獲取浦夷,顏色也是6位十六進制的數(shù)字表示辖试。 |
android:duration | 動畫的時長,int類型劈狐,以毫秒為單位罐孝,默認(rèn)為300毫秒。 |
android:startOffset | 動畫延遲的時間肥缔,從調(diào)用start方法后開始計算莲兢,int型,毫秒為單位续膳。 |
android:repeatCount | 一個動畫的重復(fù)次數(shù)改艇,int型,”-1“表示無限循環(huán)坟岔,”1“表示動畫在第一次執(zhí)行完成后重復(fù)執(zhí)行一次谒兄,也就是兩次,默認(rèn)為0社付,不重復(fù)執(zhí)行承疲。 |
android:repeatMode | 重復(fù)模式:int型,當(dāng)一個動畫執(zhí)行完的時候應(yīng)該如何處理鸥咖。該值必須是正數(shù)或者是-1燕鸽,“reverse”會使得按照動畫向相反的方向執(zhí)行,可實現(xiàn)類似鐘擺效果啼辣∶嘣郏“repeat”會使得動畫每次都從頭開始循環(huán)。 |
android:valueType | 關(guān)鍵參數(shù)熙兔,如果該value是一個顏色,那么就不需要指定艾恼,因為動畫框架會自動的處理顏色值住涉。有intType和floatType(默認(rèn))兩種:分別說明動畫值為int和float型。 |
<objectAnimator>
屬性解釋:
同上<objectAnimator>
屬性钠绍,不多介紹舆声。
XML屬性動畫使用方法:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
R.animtor.property_animator);
set.setTarget(myObject);
set.start();
4-2-3 Java方式屬性動畫
1、ObjectAnimator:繼承自ValueAnimator,允許你指定要進行動畫的對象以及該對象 的一個屬性媳握。該類會根據(jù)計算得到的新值自動更新屬性碱屁。大多數(shù)的情況使用ObjectAnimator就足夠了,因為它使得目標(biāo)對象動畫值的處理過程變得足 夠簡單蛾找,不用像ValueAnimator那樣自己寫動畫更新的邏輯娩脾,但是ObjectAnimator有一定的限制,比如它需要目標(biāo)對象的屬性提供指定 的處理方法(譬如提供getXXX打毛,setXXX方法)柿赊,這時候你就需要根據(jù)自己的需求在ObjectAnimator和ValueAnimator中看 哪種實現(xiàn)更方便了。
ObjectAnimator類提供了ofInt幻枉、ofFloat碰声、ofObject這個三個常用的方法,這些方法都是設(shè)置動畫作用的元素熬甫、屬性胰挑、開始、結(jié)束等任意屬性值椿肩。當(dāng)屬性值(上面方法的參數(shù))只設(shè)置一個時就把通過getXXX反射獲取的值作為起點瞻颂,設(shè)置的值作為終點;如果設(shè)置兩個(參數(shù))覆旱,那么一個是開始蘸朋、另一個是結(jié)束。
特別注意:ObjectAnimator的動畫原理是不停的調(diào)用setXXX方法更新屬性值扣唱,所有使用ObjectAnimator更新屬性時的前提是Object必須聲明有g(shù)etXXX和setXXX方法藕坯。
我們通常使用ObjectAnimator設(shè)置View已知的屬性來生成動畫,而一般View已知屬性變化時都會主動觸發(fā)重繪圖操作噪沙,所以動畫會自 動實現(xiàn)炼彪;但是也有特殊情況,譬如作用Object不是View正歼,或者作用的屬性沒有觸發(fā)重繪辐马,或者我們在重繪時需要做自己的操作,那都可以通過如下方法手 動設(shè)置:
ObjectAnimator mObjectAnimator= ObjectAnimator.ofInt(view, "customerDefineAnyThingName", 0, 1).setDuration(2000);
mObjectAnimator.addUpdateListener(new AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
//int value = animation.getAnimatedValue(); 可以獲取當(dāng)前屬性值
//view.postInvalidate(); 可以主動刷新
//view.setXXX(value);
//view.setXXX(value);
//......可以批量修改屬性
}
});
如下是一個我在項目中的Y軸3D旋轉(zhuǎn)動畫實現(xiàn)實例:
ObjectAnimator.ofFloat(view, "rotationY", 0.0f, 360.0f).setDuration(1000).start();
2局义、PropertyValuesHolder:多屬性動畫同時工作管理類喜爷。有時候我們需要同時修改多個屬性,那就可以用到此類萄唇,具體如下:
PropertyValuesHolder a1 = PropertyValuesHolder.ofFloat("alpha", 0f, 1f);
PropertyValuesHolder a2 = PropertyValuesHolder.ofFloat("translationY", 0, viewWidth);
......
ObjectAnimator.ofPropertyValuesHolder(view, a1, a2, ......).setDuration(1000).start();
如上代碼就可以實現(xiàn)同時修改多個屬性的動畫啦檩帐。
3、ValueAnimator:屬性動畫中的時間驅(qū)動另萤,管理著動畫時間的開始湃密、結(jié)束屬性值诅挑,相應(yīng)時間屬性值計算方法等。包含所有計算動畫值的核心函數(shù)以及每一個動畫時間節(jié)點上的信息泛源、一個動畫是否重復(fù)拔妥、是否監(jiān)聽更新事件等,并且還可以設(shè)置自定義的計算類型达箍。
特別注意:ValueAnimator只是動畫計算管理驅(qū)動没龙,設(shè)置了作用目標(biāo),但沒有設(shè)置屬性幻梯,需要通過updateListener里設(shè)置屬性才會生效兜畸。
ValueAnimator animator = ValueAnimator.ofFloat(0, mContentHeight); //定義動畫
animator.setTarget(view); //設(shè)置作用目標(biāo)
animator.setDuration(5000).start();
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation){
float value = (float) animation.getAnimatedValue();
view.setXXX(value); //必須通過這里設(shè)置屬性值才有效
view.mXXX = value; //不需要setXXX屬性方法
}
});
大眼看上去可以發(fā)現(xiàn)和ObjectAnimator沒啥區(qū)別,實際上正是由于ValueAnimator不直接操作屬性值碘梢,所以要操作對象的屬性可以不需要setXXX與getXXX方法咬摇,你完全可以通過當(dāng)前動畫的計算去修改任何屬性。
4煞躬、AnimationSet:動畫集合肛鹏,提供把多個動畫組合成一個組合的機制,并可設(shè)置動畫的時序關(guān)系恩沛,如同時播放在扰、順序播放或延遲播放。具體使用方法比較簡單雷客,如下:
ObjectAnimator a1 = ObjectAnimator.ofFloat(view, "alpha", 1.0f, 0f);
ObjectAnimator a2 = ObjectAnimator.ofFloat(view, "translationY", 0f, viewWidth);
......
AnimatorSet animSet = new AnimatorSet();
animSet.setDuration(5000);
animSet.setInterpolator(new LinearInterpolator());
//animSet.playTogether(a1, a2, ...); //兩個動畫同時執(zhí)行
animSet.play(a1).after(a2); //先后執(zhí)行
......//其他組合方式
animSet.start();
5芒珠、Evaluators相關(guān)類解釋: Evaluators就是屬性動畫系統(tǒng)如何去計算一個屬性值。它們通過Animator提供的動畫的起始和結(jié)束值去計算一個動畫的屬性值搅裙。
IntEvaluator:整數(shù)屬性值皱卓。
FloatEvaluator:浮點數(shù)屬性值。
ArgbEvaluator:十六進制color屬性值部逮。
TypeEvaluator:用戶自定義屬性值接口娜汁,譬如對象屬性值類型不是int、float兄朋、color類型掐禁,你必須實現(xiàn)這個接口去定義自己的數(shù)據(jù)類型。
既然說到這了颅和,那就來個例子吧傅事,譬如我們需要實現(xiàn)一個自定義屬性類型和計算規(guī)則的屬性動畫,如下類型float[]:
ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(5000);
valueAnimator.setObjectValues(new float[2]); //設(shè)置屬性值類型
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setEvaluator(new TypeEvaluator<float[]>()
{
@Override
public float[] evaluate(float fraction, float[] startValue,
float[] endValue)
{
//實現(xiàn)自定義規(guī)則計算的float[]類型的屬性值
float[] temp = new float[2];
temp[0] = fraction * 2;
temp[1] = (float)Math.random() * 10 * fraction;
return temp;
}
});
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
float[] xyPos = (float[]) animation.getAnimatedValue();
view.setHeight(xyPos[0]); //通過屬性值設(shè)置View屬性動畫
view.setWidth(xyPos[1]); //通過屬性值設(shè)置View屬性動畫
}
});
6峡扩、Interpolators相關(guān)類解釋:
AccelerateDecelerateInterolator:先加速后減速蹭越。
AccelerateInterpolator:加速。
DecelerateInterpolator:減速有额。
AnticipateInterpolator:先向相反方向改變一段再加速播放。
AnticipateOvershootInterpolator:先向相反方向改變,再加速播放巍佑,會超出目標(biāo)值然后緩慢移動至目標(biāo)值茴迁,類似于彈簧回彈。
BounceInterpolator:快到目標(biāo)值時值會跳躍萤衰。
CycleIinterpolator:動畫循環(huán)一定次數(shù)堕义,值的改變?yōu)橐徽液瘮?shù):Math.sin(2 * mCycles * Math.PI * input)。
LinearInterpolator:線性均勻改變脆栋。
OvershottInterpolator:最后超出目標(biāo)值然后緩慢改變到目標(biāo)值倦卖。
TimeInterpolator:一個允許自定義Interpolator的接口,以上都實現(xiàn)了該接口椿争。
舉個例子怕膛,就像系統(tǒng)提供的標(biāo)準(zhǔn)API一樣,如下就是加速插值器的實現(xiàn)代碼秦踪,我們自定義時也可以類似實現(xiàn):
//開始很慢然后不斷加速的插值器褐捻。
public class AccelerateInterpolator implements Interpolator {
private final float mFactor;
private final double mDoubleFactor;
public AccelerateInterpolator() {
mFactor = 1.0f;
mDoubleFactor = 2.0;
}
......
//input 0到1.0。表示動畫當(dāng)前點的值椅邓,0表示開頭柠逞,1表示結(jié)尾。
//return 插值景馁。值可以大于1超出目標(biāo)值板壮,也可以小于0突破低值。
@Override
public float getInterpolation(float input) {
//實現(xiàn)核心代碼塊
if (mFactor == 1.0f) {
return input * input;
} else {
return (float)Math.pow(input, mDoubleFactor);
}
}
}
綜上可以發(fā)現(xiàn)合住,我們可以使用現(xiàn)有系統(tǒng)提供標(biāo)準(zhǔn)的東東實現(xiàn)屬性動畫绰精,也可以通過自定義繼承相關(guān)接口實現(xiàn)自己的動畫,只要實現(xiàn)上面提到的那些主要方法即可聊疲。
4-2-4 Java屬性動畫拓展之ViewPropertyAnimator動畫
在Android API 12時茬底,View中添加了animate方法,具體如下:
public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityEventSource {
......
/**
* This method returns a ViewPropertyAnimator object, which can be used to animate
* specific properties on this View.
*
* @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View.
*/
public ViewPropertyAnimator animate() {
if (mAnimator == null) {
mAnimator = new ViewPropertyAnimator(this);
}
return mAnimator;
}
......
}
可以看見通過View的animate()方法可以得到一個ViewPropertyAnimator的屬性動畫(有人說他沒有繼承Animator類获洲,是的阱表,他是成員關(guān)系,不是之前那種繼承關(guān)系)贡珊。
ViewPropertyAnimator提供了一種非常方便的方法為View的部分屬性設(shè)置動畫(切記最爬,是部分屬性),它可以直接使用一個 Animator對象設(shè)置多個屬性的動畫门岔;在多屬性設(shè)置動畫時爱致,它比 上面的ObjectAnimator更加牛逼、高效寒随,因為他會管理多個屬性的invalidate方法統(tǒng)一調(diào)運觸發(fā)糠悯,而不像上面分別調(diào)用帮坚,所以還會有一些 性能優(yōu)化。如下就是一個例子:
myView.animate().x(0f).y(100f).start();
4-2-5 Java屬性動畫拓展之LayoutAnimator容器布局動畫
Property動畫系統(tǒng)還提供了對ViewGroup中View添加時的動畫功能互艾,我們可以用LayoutTransition對 ViewGroup中的View進行動畫設(shè)置顯示试和。LayoutTransition的動畫效果都是設(shè)置給ViewGroup,然后當(dāng)被設(shè)置動畫的 ViewGroup中添加刪除View時體現(xiàn)出來纫普。該類用于當(dāng)前布局容器中有View添加阅悍、刪除、隱藏昨稼、顯示等時候定義布局容器自身的動畫和View的動 畫节视,也就是說當(dāng)在一個LinerLayout中隱藏一個View的時候,我們可以自定義 整個由于LinerLayout隱藏View而改變的動畫假栓,同時還可以自定義被隱藏的View自己消失時候的動畫等寻行。
我們可以發(fā)現(xiàn)LayoutTransition類中主要有五種容器轉(zhuǎn)換動畫類型,具體如下:
LayoutTransition.APPEARING:當(dāng)View出現(xiàn)或者添加的時候View出現(xiàn)的動畫但指。
LayoutTransition.CHANGE_APPEARING:當(dāng)添加View導(dǎo)致布局容器改變的時候整個布局容器的動畫寡痰。
LayoutTransition.DISAPPEARING:當(dāng)View消失或者隱藏的時候View消失的動畫。
LayoutTransition.CHANGE_DISAPPEARING:當(dāng)刪除或者隱藏View導(dǎo)致布局容器改變的時候整個布局容器的動畫棋凳。
LayoutTransition.CHANGE:當(dāng)不是由于View出現(xiàn)或消失造成對其他View位置造成改變的時候整個布局容器的動畫拦坠。
XML方式使用系統(tǒng)提供的默認(rèn)LayoutTransition動畫:
我們可以通過如下方式使用系統(tǒng)提供的默認(rèn)ViewGroup的LayoutTransition動畫:
android:animateLayoutChanges=”true”
在ViewGroup添加如上xml屬性默認(rèn)是沒有任何動畫效果的,因為前面說了剩岳,該動畫針對于ViewGroup內(nèi)部東東發(fā)生改變時才有效贞滨,所以當(dāng)我們設(shè)置如上屬性然后調(diào)運ViewGroup的addView、removeView方法時就能看見系統(tǒng)默認(rèn)的動畫效果了拍棕。
還有一種就是通過如下方式設(shè)置:
android:layoutAnimation=”@anim/customer_anim”
通過這種方式就能實現(xiàn)很多吊炸天的動畫晓铆。
Java方式使用系統(tǒng)提供的默認(rèn)LayoutTransition動畫:
在使用LayoutTransition時,你可以自定義這幾種事件類型的動畫绰播,也可以使用默認(rèn)的動畫骄噪,總之最終都是通過 setLayoutTransition(LayoutTransition lt)方法把這些動畫以一個LayoutTransition對象設(shè)置給一個ViewGroup。
譬如實現(xiàn)如上Xml方式的默認(rèn)系統(tǒng)LayoutTransition動畫如下:
mTransitioner = new LayoutTransition();
mViewGroup.setLayoutTransition(mTransitioner);
稍微再高端一點吧蠢箩,我們來自定義這幾類事件的動畫链蕊,分別實現(xiàn)他們,那么你可以像下面這么處理:
mTransitioner = new LayoutTransition();
......
ObjectAnimator anim = ObjectAnimator.ofFloat(this, "scaleX", 0, 1);
......//設(shè)置更多動畫
mTransition.setAnimator(LayoutTransition.APPEARING, anim);
......//設(shè)置更多類型的動畫 mViewGroup.setLayoutTransition(mTransitioner);
到此通過LayoutTransition你就能實現(xiàn)類似小米手機計算器切換普通型和科學(xué)型的炫酷動畫了谬泌。
5 Android動畫總結(jié)
到此Android動畫基本已經(jīng)描述OK了滔韵,也就這么三大類,尤其是屬性動畫更加一籌掌实。但是特別說一句陪蜻,上面基本都沒有提及到各種動畫的 Listener接口,原因是這個玩意太簡單贱鼻,所以不提了宴卖,相信你會監(jiān)聽View的onClickListener就一定會觸類旁通動畫的 Listener方法的滋将。有了這些基礎(chǔ)相信無論是自定義控件時還是自定義動畫時都會起到直接的指導(dǎo)參考作用。其實對于Android的動畫實現(xiàn)遠(yuǎn)遠(yuǎn)不止現(xiàn) 在提到的這些症昏,但是這些又是基礎(chǔ)耕渴,所以后面還會寫文章說說Android提供的其他動畫參考工具類的。
現(xiàn)在我們繼續(xù)沿用官方的對比齿兔,翻譯一下這些動畫的區(qū)別,具體如下(點我參看原文How Property Animation Differs from View Animation):
View動畫:
View動畫只能夠為View添加動畫础米,如果想為非View對象添加動畫須自己實現(xiàn)分苇;且View動畫支持的種類很少;尤其是他改變的是View的繪制效果屁桑,View的屬性沒有改變医寿,其位置與大小都不變; View動畫代碼量少蘑斧,使用簡單方便靖秩。
Property動畫:
彌補了View動畫的缺陷,你可以為一個對象的任意屬性添加動畫竖瘾,對象自己的屬性會被真的改變沟突;當(dāng)對象的屬性變化的時候,屬性動畫會自動刷新屏幕捕传;屬性動畫改變的是對象的真實屬性惠拭,而且屬性動畫不止用于View,還可以用于任何對象庸论。
作者: 一點點征服