[TOC]
Property Animation
屬性動畫系統(tǒng)是一個強(qiáng)大的框架,幾乎可以將任何東西動畫化。您可以定義一個動畫以隨時間更改任何對象屬性,而不管它是否繪制到屏幕。屬性動畫在指定的時間長度內(nèi)更改屬性(對象中的字段)值。你可以指定要動畫的對象屬性。例如對象在屏幕上的位置,要為其設(shè)置動畫的時間長度以及要在其間進(jìn)行動畫化的值。
屬性動畫系統(tǒng)允許開發(fā)者定義動畫的以下特征:
- 1:Duration:你可以指定動畫的持續(xù)時間。
默認(rèn)長度為300 ms。 - 2:Time interpolation:你可以指定如何根據(jù)動畫當(dāng)前所用時間計算屬性的值。
- 3:Repeat count and behavior: 你可以指定是否在到達(dá)持續(xù)時間結(jié)束時重復(fù)播放動畫,以及重復(fù)播放動畫的次數(shù)。 還可以指定是否要相反地播放動畫。 將其設(shè)置為反向播放動畫向前,然后反復(fù)向后,直到達(dá)到重復(fù)次數(shù)。
- 4:Animator sets:您可以將動畫組合成Sets,可以設(shè)置Sets的播放方式,一起播放或順序播放或在指定的延遲之后。
- 5:Frame refresh delay:你可以指定刷新動畫幀的頻率。 默認(rèn)設(shè)置為每10 ms更新一次,但是應(yīng)用程序刷新幀的速度最終取決于系統(tǒng)整體的繁忙程度,以及系統(tǒng)可以為底層定時器服務(wù)的速度。
Property Animation 的工作原理:
首先,我們來通過一個例子查看一下動畫是如何工作的,圖1描繪了一個假設(shè)的對象,是x屬性水平移動的動畫。動畫的持續(xù)時間設(shè)置為40 ms,行程距離為40像素。 每10 ms,這是默認(rèn)的幀刷新率,對象水平移動10像素。 在40 ms結(jié)束時,動畫停止,物體以水平位置40結(jié)束。這是具有線性插值的動畫的示例,意味著物體以恒定的速度移動。
你還可以指定具有非線性內(nèi)插的動畫。圖2示出了對象在動畫開始時加速,并且在動畫結(jié)束時減速。 物體仍然在40毫秒內(nèi)移動40像素,但是非線性。 一開始,這個動畫加速到中途,然后從中途減速直到動畫結(jié)束。 如圖2所示,動畫開頭和結(jié)尾處的距離小于中間。
我們來詳細(xì)了解屬性動畫系統(tǒng)的重要組件如何計算動畫,如圖所示:
ValueAnimator對象跟蹤動畫的時間,例如動畫已運(yùn)行多長時間,以及動畫所屬屬性的當(dāng)前值。ValueAnimator封裝了TimeInterpolator,它定義了動畫插值,還有一個TypeEvaluator,它定義了如何計算動畫屬性的值。例如,在圖2中,使用的TimeInterpolator將為AccelerateDecelerateInterpolator,TypeEvaluator將為IntEvaluator。
要啟動動畫,創(chuàng)建一個ValueAnimator,并為其創(chuàng)建動畫的屬性、動畫持續(xù)時間以及它的開始和結(jié)束值,然后調(diào)用start()方法開始動畫。在整個動畫過程中,ValueAnimator根據(jù)動畫的持續(xù)時間和經(jīng)過多少時間,計算0到1之間的經(jīng)過分?jǐn)?shù)。經(jīng)過的分?jǐn)?shù)表示動畫完成的時間百分比,0表示0%,1表示100%。
例如,在圖1中,t = 10ms時的經(jīng)過分?jǐn)?shù)為0.25,因為總持續(xù)時間為t =40ms。當(dāng)ValueAnimator完成計算經(jīng)過的分?jǐn)?shù)時,它調(diào)用當(dāng)前設(shè)置的TimeInterpolator,以計算內(nèi)插分?jǐn)?shù)(編者按:不是有個插值器么,定義了動畫的快慢方式,比如勻速,先加速后減速)。將經(jīng)過的時間分?jǐn)?shù)映射到考慮到插值的新分?jǐn)?shù)(編者按:最后根據(jù)這個新分?jǐn)?shù)來計算實(shí)際的百分比,在上面是實(shí)際的運(yùn)動距離)。例如,在圖2中,由于動畫緩慢加速,所以在t= 10 ms時,內(nèi)插分?jǐn)?shù)約為.15,小于經(jīng)過的時間分?jǐn)?shù).25。 在圖1中,插值分?jǐn)?shù)總是與經(jīng)過分?jǐn)?shù)相同。
當(dāng)計算插值分?jǐn)?shù)時,ValueAnimator將根據(jù)插值分?jǐn)?shù),起始值和動畫的結(jié)束值,調(diào)用相應(yīng)的TypeEvaluator來計算您要動畫化的屬性值。 例如,在圖2中,t = 10 ms時插值分?jǐn)?shù)為.15,因此此時的屬性值為.15 X(40 - 0)或6。
Property Animation與View Animation有哪些不同
Android 的ViewAnimation系統(tǒng)只提供了給View對象動畫處理的功能,因此,如果你想為非View對象設(shè)置動畫效果,則必須自己去實(shí)現(xiàn)相關(guān)代碼。ViewAnimation系統(tǒng)本身也有限制,它只將View的幾個方面暴露出來讓我們來實(shí)現(xiàn)動畫,例如視圖的縮放和旋轉(zhuǎn),但是并沒有提供給我們背景顏色(編者按:背景顏色屬于View的屬性,我們可以使用屬性動畫來控制它)。
ViewAnimation系統(tǒng)的另一個缺點(diǎn)是它只修改了View的繪制位置,而不是實(shí)際的View本身。例如,如果你通過ViewAnimation系統(tǒng)實(shí)現(xiàn)一個按鈕在屏幕上移動的動畫,則動畫可以正確繪制,但你可以單擊按鈕的實(shí)際位置不會更改(編者按:也就你點(diǎn)擊的區(qū)域不會改變,你可以自己實(shí)現(xiàn)來看,雖然View移動了,但是點(diǎn)擊區(qū)域還是原來的位置),因此你需要來處理此問題(編者按:如果你知識需要一個動畫,這樣就可以了)。
使用屬性動畫的話,就沒有上面所說的問題。你可以對任何對象(視圖和非視圖)的任何屬性進(jìn)行動畫處理,并且對象本身實(shí)際上進(jìn)行了修改。屬性動畫系統(tǒng)在執(zhí)行動畫的方式也更加強(qiáng)大。在高級別上,你可以分配animators (編者按:這個地方官方給的是animators)給你想要執(zhí)行動畫的屬性,例如顏色,位置或大小,并且可以定義動畫的方面(aspects),例如多個animators的插值(編者按:插值器)和同步。然而,View Animation系統(tǒng)需要較少的時間來設(shè)置,并且需要較少的代碼來寫入。如果View Animation系統(tǒng)就可以完成了你想要的動畫效果,則不需要使用屬性動畫。如果使用情況出現(xiàn)的話(編者按:個人認(rèn)為是如果需要的話),在不同情況下使用這兩種動畫系統(tǒng)也是有意義的。
用ValueAnimator進(jìn)行動畫處理
ValueAnimator類允許你通過指定一組int,float或顏色值來動畫化。通過調(diào)用其中一種工廠方法獲取ValueAnimator:ofInt(),ofFloat()或ofObject()。例如:
ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
animation.setDuration(1000);
animation.start();
(編者按:這里只是對值進(jìn)行了處理,并沒有涉及到目標(biāo)對象以及我們要操作的屬性)
在此代碼中,當(dāng)start()方法運(yùn)行時,ValueAnimator將開始計算0到100之間的動畫值,持續(xù)時間為1000 ms。
你還可以通過執(zhí)行以下操作來指定自定義類型進(jìn)行動畫處理:
ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();
(編者按:這里需要我們自己去計算實(shí)際的動畫值,你傳入的是object,系統(tǒng)又不知道該怎么去幫你計算,所以只能自行處理,這里是用MyTypeEvaluator繼承自TypeEvaluator來進(jìn)行處理)
在此代碼中,當(dāng)start()方法運(yùn)行時,ValueAnimator將使用MyTypeEvaluator提供的邏輯持續(xù)1000 ms,在startPropertyValue和endPropertyValue之間開始計算動畫值。
你可以通過向ValueAnimator對象添加AnimatorUpdateListener來使用動畫值,如以下代碼所示:
animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator updatedAnimation) {
// You can use the animated value in a property that uses the
// same type as the animation. In this case, you can use the
// float value in the translationX property.
float animatedValue = (float)updatedAnimation.getAnimatedValue();
textView.setTranslationX(animatedValue);
}
});
在onAnimationUpdate()方法中,您可以訪問更新的動畫值,并在其中一個視圖的屬性中使用它。
用ObjectAnimator進(jìn)行動畫處理
ObjectAnimator是ValueAnimator的一個子類,將ValueAnimator的定時引擎和值計算與將目標(biāo)對象的命名屬性動畫化的能力相結(jié)合。這使得動畫化任何對象更容易,因為不再需要實(shí)ValueAnimator.AnimatorUpdateListener,因為動畫屬性會自動更新。
實(shí)例化一個ObjectAnimator類似于一個ValueAnimator,但是您還可以指定該對象的屬性(作為一個字符串)的名稱以及值之間的動畫值:
ObjectAnimator animation = ObjectAnimator.ofFloat(textView, "translationX", 100f);
animation.setDuration(1000);
animation.start();
要使ObjectAnimator正確更新屬性,必須執(zhí)行以下操作:
一、正在動畫的對象屬性必須以set <PropertyName>()的形式具有setter函數(shù)(以駝峰命名的形式)。因為ObjectAnimator在動畫過程中自動更新屬性,所以它必須能夠使用此setter方法訪問該屬性。(編者按:執(zhí)行的過程是強(qiáng)制將你傳遞的字符串的第一個字母大寫然后和set進(jìn)行拼接,組成調(diào)用對話對象的set方法)
例如,如果屬性名稱為foo,則需要具有setFoo()方法。如果此setter方法不存在,有三個選項:
- 1:如果有權(quán)這樣做,將setter方法添加到類中。
- 2:使用有權(quán)更改的包裝類,并使該包裝器使用有效的setter方法接收該值并將其轉(zhuǎn)發(fā)到原始對象。
- 3:改用ValueAnimator。
二:如果在ObjectAnimator的方法之一中為values ...參數(shù)只指定了一個值,那么那個值假定是動畫的結(jié)束值。因此,您正在動畫的對象屬性必須具有用于獲取動畫起始值的getter函數(shù)。 getter函數(shù)必須以get<PropertyName>()的形式。 例如,如果屬性名稱是foo,則需要使用getFoo()方法。
三:要動畫的屬性的getter(如果需要)和setter方法必須與您指定給ObjectAnimator的起始值和結(jié)束值有相同的類型。例如,如果構(gòu)造以下ObjectAnimator,則必須具有targetObject.setPropName(float)和targetObject.getPropName(float):
ObjectAnimator.ofFloat(targetObject, "propName", 1f)
四:根據(jù)您所動畫的屬性或?qū)ο?,您可能需要在視圖上調(diào)用invalidate()方法來強(qiáng)制屏幕使用更新的動畫值重新繪制自己。你可以在onAnimationUpdate()回調(diào)中執(zhí)行此操作。例如,動畫化Drawable對象的color屬性只會導(dǎo)致在Drawable對象重新繪制時更新屏幕。View上的所有屬性setter(如setAlpha()和setTranslationX())都會使View無效,因此在使用新值調(diào)用這些方法時,不需要使View無效。 有關(guān)偵聽器的更多信息,請參閱有關(guān)動態(tài)偵聽器的部分。
使用AnimatorSet來控制多個動畫
在許多情況下,你想要播放依賴于其他動畫開始或結(jié)束的動畫。Android系統(tǒng)允許將動畫捆綁在一起成AnimatorSet,以便可以指定是同時,順序還是在指定的延遲之后啟動動畫。 您也可以將AnimatorSet對象嵌套在彼此中。
從彈跳球Demo(為了簡化而有所修改)獲取的以下示例代碼以下列方式展示下列的Animators。
- 1:Plays bounceAnim
- 2:Plays squashAnim1,squashAnim2,stretchAnim1和stretchAnim2。
- 3:Plays bounceBackAnim.
- 4:Plays fadeAnim.
有關(guān)如何使用動畫組合的更完整的示例,請參閱APIDemos中的 Bouncing Balls示例。
Animation Listeners
你可以在動畫持續(xù)時間內(nèi)收聽下面介紹的listeners 的重要事件。
一:Animator.AnimatorListener
- 1:onAnimationStart() - 動畫啟動時調(diào)用。
- 2:onAnimationEnd() - 動畫結(jié)束時調(diào)用。
- 3:onAnimationRepeat() - 當(dāng)動畫重復(fù)時調(diào)用。
- 4:onAnimationCancel() - 當(dāng)動畫被取消時調(diào)用。 取消的動畫也會調(diào)用OnAnimationEnd(),無論它們?nèi)绾谓Y(jié)束。
二:ValueAnimator.AnimatorUpdateListener
onAnimationUpdate() - 在動畫的每個幀上調(diào)用。(默認(rèn)的幀刷新率是10ms每次),監(jiān)聽此事件以使用ValueAnimator在動畫期間生成的計算值。要使用該值,使用傳遞給事件的ValueAnimator對象的getAnimatedValue()方法獲取當(dāng)前動畫值。 如果你使用ValueAnimator,則需要實(shí)現(xiàn)此監(jiān)聽器。
根據(jù)你要動畫的屬性或?qū)ο螅赡苄枰谝晥D上調(diào)用invalidate(),以強(qiáng)制屏幕區(qū)域使用新的動畫值重新繪制。 例如,當(dāng)Drawable對象重新繪制時,可以對Drawable對象的color屬性進(jìn)行動畫化,只會導(dǎo)致屏幕更新。 View上的所有屬性setter(如setAlpha()和setTranslationX())都會使View無效,因此在使用新值調(diào)用這些方法時,不需要使View無效。(前面已經(jīng)介紹過了)
如果你不想實(shí)現(xiàn)Animator.AnimatorListener接口的所有方法,可以擴(kuò)展AnimatorListenerAdapter類。 AnimatorListenerAdapter類提供了可以選擇覆蓋的方法的空實(shí)現(xiàn)。
(編者按:你如果實(shí)現(xiàn)Animator.AnimatorListener接口接口的話需要實(shí)現(xiàn)下面這四個方法。
void onAnimationStart(Animator animation);
void onAnimationEnd(Animator animation);
void onAnimationCancel(Animator animation);
void onAnimationRepeat(Animator animation);
如果你不想實(shí)現(xiàn)這么多的話,比如你只需要一個的實(shí)現(xiàn),你就可以使用AnimatorListenerAdapter類,這個類繼承自Animator.AnimatorListener接口和Animator.AnimatorPauseListener接口,這個接口里有兩個方法
void onAnimationPause(Animator animation);
void onAnimationResume(Animator animation);
所以AnimatorListenerAdapter類里面有上面六個方法的實(shí)現(xiàn),你可以任意選擇一個來進(jìn)行實(shí)現(xiàn))
谷歌官方給了個栗子:
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
balls.remove(((ObjectAnimator)animation).getTarget());
}
Animating Layout Changes to ViewGroups
屬性動畫系統(tǒng)提供了對ViewGroup對象進(jìn)行動畫更改的功能,同時也為View對象本身提供了一種簡單的方法。
你可以使用LayoutTransition類為ViewGroup中的布局設(shè)置更改動畫。ViewGroup中的View可以在ViewGroup中添加或從ViewGroup中刪除時或當(dāng)你使用VISIBLE,INVISIBLE或GONE調(diào)用View的setVisibility()方法時,看到出現(xiàn)和消失的動畫。當(dāng)你添加或刪除視圖時,ViewGroup中的其余視圖也可以動畫的進(jìn)入它們新的位置。
你可以通過調(diào)用setAnimator()并傳遞Animator對象和傳遞在LayoutTransition對象中定義以下常亮之一來設(shè)置動畫:
LayoutTransition 類中定義的常數(shù):
- 1:APPEARING - 指示在容器中出現(xiàn)的項目上運(yùn)行的動畫的標(biāo)志。
- 2:CHANGE_APPEARING - 指示由于容器中出現(xiàn)新項目而改變的項目上運(yùn)行的動畫的標(biāo)志。
- 3:DISAPPEARING - 表示在從容器中消失的項目上運(yùn)行的動畫的標(biāo)志。
- 4:CHANGE_DISAPPEARING - 指示由于項目從容器中消失而改變的項目上運(yùn)行的動畫的標(biāo)志。
(編者按:setAnimator源碼如下:)
public void setAnimator(int transitionType, Animator animator) {
switch (transitionType) {
case CHANGE_APPEARING:
mChangingAppearingAnim = animator;
break;
case CHANGE_DISAPPEARING:
mChangingDisappearingAnim = animator;
break;
case CHANGING:
mChangingAnim = animator;
break;
case APPEARING:
mAppearingAnim = animator;
break;
case DISAPPEARING:
mDisappearingAnim = animator;
break;
}
}
你可以為這四種類型的事件定義自己的動畫,以及自定義布局轉(zhuǎn)換的外觀,或者只是告訴動畫系統(tǒng)使用默認(rèn)動畫。API Demos中的LayoutAnimations示例顯示了如何為布局轉(zhuǎn)換定義動畫,然后在要動畫化的View對象上設(shè)置動畫。
LayoutAnimationsByDefault及其相應(yīng)的layout_animations_by_default.xml布局資源文件顯示如何啟用XML中ViewGroups的默認(rèn)布局轉(zhuǎn)換。 你唯一需要做的是為ViewGroup設(shè)置android:animateLayoutchanges屬性為true。 例如:
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/verticalContainer"
android:animateLayoutChanges="true" />
將此屬性設(shè)置為true將自動生成從ViewGroup添加或刪除的視圖以及ViewGroup中的其余視圖的動畫。
Using a TypeEvaluator
如果要為Android系統(tǒng)未知的類型設(shè)置動畫,您可以通過實(shí)現(xiàn)TypeEvaluator接口來創(chuàng)建自己的evaluator 。Android系統(tǒng)已知的類型是int,float或顏色,分別對應(yīng)IntEvaluator,F(xiàn)loatEvaluator和ArgbEvaluator類型。
在在TypeEvaluator接口中只有一種方法,那就是evaluate()方法。這允許您使用的animator 在動畫的當(dāng)前位置為動畫屬性返回適當(dāng)?shù)闹怠?br>
(編者按:接口源碼如下)
public interface TypeEvaluator<T> {
/**
* This function returns the result of linearly interpolating the start and end values, with
* <code>fraction</code> representing the proportion between the start and end values. The
* calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
* and <code>t</code> is <code>fraction</code>.
*
* @param fraction The fraction from the starting to the ending values
* @param startValue The start value.
* @param endValue The end value.
* @return A linear interpolation between the start and end values, given the
* <code>fraction</code> parameter.
*/
public T evaluate(float fraction, T startValue, T endValue);
}
FloatEvaluator類:
/**
* This evaluator can be used to perform type interpolation between <code>float</code> values.
*/
public class FloatEvaluator implements TypeEvaluator<Number> {
/**
* This function returns the result of linearly interpolating the start and end values, with
* <code>fraction</code> representing the proportion between the start and end values. The
* calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
* and <code>t</code> is <code>fraction</code>.
*
* @param fraction The fraction from the starting to the ending values
* @param startValue The start value; should be of type <code>float</code> or
* <code>Float</code>
* @param endValue The end value; should be of type <code>float</code> or <code>Float</code>
* @return A linear interpolation between the start and end values, given the
* <code>fraction</code> parameter.
*/
public Float evaluate(float fraction, Number startValue, Number endValue) {
float startFloat = startValue.floatValue();
return startFloat + fraction * (endValue.floatValue() - startFloat);
}
}
(編者按:這個地方跟官方的不一樣,這里我才用的是API25的源碼,可以看出這就是一個小學(xué)的計算。。。)
注意:當(dāng)ValueAnimator(或ObjectAnimator)運(yùn)行時,它會計算動畫的當(dāng)前經(jīng)過分?jǐn)?shù)(0到1之間的值),然后根據(jù)所使用的內(nèi)插器計算出考慮到插值器的插值分?jǐn)?shù)(也就是實(shí)際的運(yùn)行分?jǐn)?shù))。 插值分?jǐn)?shù)是您的TypeEvaluator通過分?jǐn)?shù)參數(shù)獲得的分?jǐn)?shù),因此在計算動畫值時不需要考慮插值器。
Using Interpolators
插值器定義如何根據(jù)時間的函數(shù)計算動畫中的特定值。 例如,你可以指定動畫在整個動畫中線性發(fā)生,這意味著動畫在整個時間內(nèi)均勻移動,或者你可以指定使用非線性時間的動畫,例如,在開始或結(jié)束時使用加速或減速 動畫。動畫系統(tǒng)中的插值器從Animators接收代表動畫經(jīng)過時間的分?jǐn)?shù)。插值器修改這個分?jǐn)?shù)(這個分?jǐn)?shù)只和時間相關(guān)),以符合它在提供的類型。(編者按:在源碼中有兩個分?jǐn)?shù),一個是在插值器之前的,這個分?jǐn)?shù)只和時間相關(guān),另一個是經(jīng)過插值器修改過的,這個就是實(shí)際運(yùn)行的分?jǐn)?shù),只有在勻速運(yùn)動的時候兩個分?jǐn)?shù)是相同的)。
Android系統(tǒng)在android.view.animation包中提供了一組常見的插件。 如果這些都不符合您的需求,您可以實(shí)現(xiàn)TimeInterpolator界面并創(chuàng)建自己的。
例如,下面比較默認(rèn)提供的插值器AccelerateDecelerateInterpolator和LinearInterpolator計算插值分?jǐn)?shù)的不同。
AccelerateDecelerateInterpolator
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
LinearInterpolator
public float getInterpolation(float input) {
return input;
}
下表表示這些內(nèi)插器為持續(xù)1000ms的動畫計算的近似值
ms elapsed | Linear | Accelerate/Decelerate |
---|---|---|
0 | 0 | 0 |
200 | 0.2 | 0.1 |
400 | 0.4 | 0.345 |
600 | 0.6 | 0.8 |
800 | 0.8 | 0.9 |
1000 | 1.0 | 1.0 |
Specifying Keyframes
(編者按:先來看一下源碼對于Keyframes是怎么定義的-->該類保存動畫的時間/值對。)
一個Keyframes保存一個時間/值對,在開發(fā)者定義的一個特定狀態(tài)在動畫的特定時間。每一個keyframe也能夠擁有自己的插值器在前一個keyframe和這個keyframe的時間間隔內(nèi)去控制動畫的行為。
要實(shí)例化一個Keyframe 對象,你必須使用一個工廠方法,即ofInt(),ofFloat()或orObject()來獲取Keyframe的適當(dāng)類型。(編者按:整篇文章對ofInt等方法都成為factory methods,有知道的朋友可以給我留言)
然后調(diào)用ofKeyframe()方法來獲取一個PropertyValuesHolder對象。一旦擁有該對象,你可以通過傳遞PropertyValuesHolder對象和the object獲得一個animator 去實(shí)現(xiàn)動畫。
以下代碼段演示了如何執(zhí)行此操作:
Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)
rotationAnim.setDuration(5000ms);
有關(guān)如何使用keyframe的更完整的示例,請參閱APIDemos中的MultiPropertyAnimation示例。
Animating Views
屬性動畫系統(tǒng)允許View對象的流線型動畫,并且相比視圖動畫系統(tǒng)有很多優(yōu)點(diǎn)。視圖動畫系統(tǒng)通過更改繪制方式來轉(zhuǎn)換View對象。這是在每個視圖的容器中處理的,因為View本身沒有要處理的屬性。這導(dǎo)致View被動畫化,但是在View對象本身沒有改變。這導(dǎo)致即使它被繪制在屏幕上的不同位置,對象仍然存在于其原始位置的行為。(編者按:之前提到過,點(diǎn)擊區(qū)域并沒有發(fā)生任何的變化),在Android 3.0中,添加了新的屬性和相應(yīng)的getter和setter方法來消除這個缺點(diǎn)。
通過更改View對象中的屬性,屬性動畫系統(tǒng)可以在屏幕上動畫化視圖。 另外,Views也會自動調(diào)用invalidate()方法,以便在其屬性更改時刷新屏幕(編者按:invalidate()方法會調(diào)用draw方法進(jìn)行重新繪制,在是用Scroller實(shí)現(xiàn)彈性動畫的時候會使用到這一點(diǎn))。
View中便于屬性動畫的新屬性有:
- 1:translationX and translationY 這些屬性控制視圖位于其左側(cè)和頂部坐標(biāo)中由其布局容器設(shè)置的三角形。(編者按:我自己的理解是移動前View的左上角和移動后View的左上角組成的三角形,對不對不清楚)
- 2:rotation, rotationX, and rotationY:這些屬性控制2D(旋轉(zhuǎn)屬性)中的旋轉(zhuǎn)和繞樞軸點(diǎn)的3D旋轉(zhuǎn)。
- 3:scaleX and scaleY:這些屬性控制視圖圍繞其樞軸點(diǎn)的2D縮放。
- 4:pivotX and pivotY: 這些屬性控制樞軸點(diǎn)的位置,旋轉(zhuǎn)和縮放變換中心都是在該位置。 默認(rèn)情況下,樞軸點(diǎn)位于對象的中心。
- 5:x and y:這些是簡單的實(shí)用屬性,用于在其容器中描述View的最終位置,作為mLeft和mTop以及translationX和translationY值之和。
- 6:表示視圖上的Alpha透明度。 默認(rèn)值為1(不透明),值為0表示完全透明(不可見)。
要為View對象的屬性(如其顏色或旋轉(zhuǎn)值)設(shè)置動畫效果,您需要做的是創(chuàng)建一個屬性動畫制作器,并指定要設(shè)置動畫的View屬性。 例如:
ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);
Animating with ViewPropertyAnimator
ViewPropertyAnimator提供了一種簡單的方式來使用單個底層的Animator對象并行地對視圖的多個屬性進(jìn)行動畫化。 它的行為非常類似于ObjectAnimator,因為它會修改視圖屬性的實(shí)際值,但在一次動畫化多個屬性時效率比ObjectAnimatior更高。另外,使用ViewPropertyAnimator的代碼更簡潔易讀。以下代碼展示了使用多個 ObjectAnimator objects,單個ObjectAnimator,以及the ViewPropertyAnimator之間的差異當(dāng)同時動畫化視圖的x和y屬性。
Multiple ObjectAnimator objects
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
One ObjectAnimator
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
ViewPropertyAnimator
myView.animate().x(50f).y(100f);
(編者按:簡直簡潔到爆有木有,下面是相關(guān)的源碼)
/**
* 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;
}
/**
* This method will cause the View's <code>x</code> property to be animated to the
* specified value. Animations already running on the property will be canceled.
*
* @param value The value to be animated to.
* @see View#setX(float)
* @return This object, allowing calls to methods in this class to be chained.
*/
public ViewPropertyAnimator x(float value) {
animateProperty(X, value);
return this;
}
/**
* This method will cause the View's <code>y</code> property to be animated to the
* specified value. Animations already running on the property will be canceled.
*
* @param value The value to be animated to.
* @see View#setY(float)
* @return This object, allowing calls to methods in this class to be chained.
*/
public ViewPropertyAnimator y(float value) {
animateProperty(Y, value);
return this;
}
有關(guān)ViewPropertyAnimator的更多詳細(xì)信息,請參閱相應(yīng)的Android Developers博客文章。
Declaring Animations in XML
屬性動畫系統(tǒng)允許您使用XML聲明屬性動畫,而不是以編程方式執(zhí)行。 通過使用XML定義動畫,您可以輕松地在多個活動中重新使用動畫,并更輕松地編輯動畫序列。
要區(qū)分使用新屬性動畫API的動畫文件與使用舊版視圖動畫框架的動畫文件,從Android 3.1開始,應(yīng)將資源動畫的XML文件保存在res / animator /目錄中。
以下屬性動畫類使用以下XML標(biāo)記支持XML聲明:
- 1:ValueAnimator - <animator>
- 2:ObjectAnimator - <objectAnimator>
- 3:AnimatorSet - <set>
要查找您可以在XML聲明中使用的屬性,請參閱Animation Resources 。以下示例順序播放兩組對象動畫,第一個是兩個一起播放的動畫。
<set android:ordering="sequentially">
<set>
<objectAnimator
android:propertyName="x"
android:duration="500"
android:valueTo="400"
android:valueType="intType"/>
<objectAnimator
android:propertyName="y"
android:duration="500"
android:valueTo="300"
android:valueType="intType"/>
</set>
<objectAnimator
android:propertyName="alpha"
android:duration="500"
android:valueTo="1f"/>
</set>
為了運(yùn)行此動畫,您必須將代碼中的XML資源inflate到AnimatorSet對象,然后在開始動畫集之前設(shè)置所有動畫的目標(biāo)對象。調(diào)用setTarget()為AnimatorSet的所有子項設(shè)置單個目標(biāo)對象。 以下代碼顯示如何執(zhí)行此操作:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
R.anim.property_animator);
set.setTarget(myObject);
set.start();
你還可以在XML中聲明ValueAnimator,如以下示例所示:
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:valueType="floatType"
android:valueFrom="0f"
android:valueTo="-100f" />
要在你的代碼中使用上面的ValueAnimator,你必須inflate 一個對象,添加AnimatorUpdateListener,獲取更新的動畫值,并將其用于其中一個視圖的屬性,如以下代碼所示:
ValueAnimator xmlAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(this,
R.animator.animator);
xmlAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator updatedAnimation) {
float animatedValue = (float)updatedAnimation.getAnimatedValue();
textView.setTranslationX(animatedValue);
}
});
xmlAnimator.start();
有關(guān)ViewPropertyAnimator的更多詳細(xì)信息,請參閱相應(yīng)的Android Developers博客文章。
Implications for UI performance
更新UI的Animators 會為動畫運(yùn)行的每個幀帶來額外的渲染工作。因此,使用資源密集型動畫可能會對你的應(yīng)用程序的性能產(chǎn)生負(fù)面影響。
為UI創(chuàng)建動畫所需的工作被添加到渲染管道的動畫階段。你可以通過啟用Profile GPU渲染和監(jiān)視動畫舞臺來確定您的動畫是否影響了您的應(yīng)用的效果。 有關(guān)更多信息,請參閱Profile GPU Rendering Walkthrough。
我的csdn博客地址:http://blog.csdn.net/zcl1359205840?viewmode=contents