Property Animation是如何運作的
- 場景一(Linear Animation):Animation要求一個物體A的x屬性在40ms內勻速地從0px變化到40px。幀的刷新率默認爲10ms/幀。
- 場景二(Not-Linear Animation):Animation要求一個物體A的x屬性在40ms內先加速後減速地從0px變化到40px。幀的刷新率默認爲10ms/幀。
- ValueAnimator對象持續跟蹤animation的時間點,如animation運行了多長時間,屬性(如場景一二中的x屬性)的當前值。
- ValueAnimator封裝了一個TimeInterpolator,TimeInterpolator定義了animation是如何插值的。ValueAnimator也封裝了一個TypeEvaluator,TypeEvaluator定義瞭如何計算屬性的值。例如示例2中,TimeInterpolator使用的是AccelerateDecelerateInterpolator和TypeEvaluator使用的是IntEvaluator
- 創建了一個ValueAnimator併爲ValueAnimator注入animation的starting value、ending value、duration value後,調用start()方法來啓動animation。
- 在Animation的整個運行過程中,ValueAnimator會基於動畫運行的時間計算出一個0-1的值,這個值被稱爲elapsed fraction。如場景一t=10ms的時刻,elapsed fraction的值爲0.25,因爲整個動畫的運行時間是40ms,所以elapsed fraction=10/40。
- 在ValueAnimator完成elapsed fraction的計算之後,它會調用TimeInterpolator去計算interpolated fraction的值。interpolated fraction會根據elapsed fraction的值來計算。例如,在場景二中,由於是緩慢加速的原因,在t=10ms的時刻,interpolated fraction的值爲0.15,會小於elapsed fraction的值0.25。而在場景一中,由於是勻速的關係,interpolated fraction的值會永遠與elapsed fraction的值一樣的。
- 在ValueAnimator完成elapsed fraction的計算之後,它會調用合適的TypeEvaluator去計算屬性的當前時刻的值,這個計算過程是基於interpolated fraction的值、starting value和ending value。例如,在場景二t=10ms的時刻點,interpolated fraction的值爲0.15,因此屬性x的值便會是0.15X(40-0)=6.
Property Animation API概覽
- Animator:它提供了創建animation最基本的結構,基本上不會直接地用到這個類,要使用這個類,必須繼承它並實現需要的功能。
- ValueAnimator:property animation主要的時間引擎,它計算了各個幀的屬性值。它包括所有核心功能:計算每個幀的相關內容,負責接收更新事件,按屬性值的類型自定義計算規則。一個動畫需要完成兩大塊內容:計算各幀的相關內容和併爲對象設置這些計算後的值。ValueAnimator不負責第二塊內容,因此你必須由ValueAnimator監聽計算值的更新並修改對象相關屬性值。
- ObjectAnimator:ValueAnimator子類,它允許你設置一個對象的屬性來完成動畫。ObjectAnimator更加常用,因爲使用它來建立動畫會更加簡單。然而,有時你需要用到ValueAnimator,因爲ObjectAnimator會有一些限制。
- AnimatorSet:把多個Animator捆綁在一起,可以讓他們同時播放,或按順序地播放、或延時一段時間播放。
- IntEvaluator:用於計算Int類型屬性值的計算器。
- FloatEvaluator:用於計算Float類型屬性值的計算器。
- ArgbEvaluator:用於計算以16進制形式表示的顏色值的計算器。
- TypeEvaluator:一個計算器接口,它允許你創建你自己的計算器。如果你正在計算一個對象屬性並不是int,float或者顏色值類型的,那麼你必須實現TypeEvaluator接口去指定如何去計算對象的屬性值。
- AccelerateDecelerateInterpolator:先加速後減速的插值器
- AccelerateInterpolator:加速插值器
- AnticipateInterpolator:先往變化的相反方向回退,然後甩到尾值的插值器
- AnticipateOvershootInterpolator:先往變化的相反方向回退,然後甩到尾值並越過尾值,再返回到尾值。
- BounceInterpolator:
- CycleInterpolator:指定重複次數的插值器
- DecelerateInterpolator:減速插值器
- LinearInterpolator:線性(勻速)插值器
- OvershootInterpolator:超過尾值再返回到尾值的插值器
- TimeInterpolator:用於實現自己的插值器的接口
使用ValueAnimator創建動畫
ofInt()
, ofFloat()
,
or ofObject()。
例如:
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000);
animation.start();
上面的例子實現了在1000ms內,值從0-1的變化。也可以提供一個自定義的Evaluator:ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();
使用ObjectAnimator創建動畫
ObjectAnimator anim = ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f);
anim.setDuration(1000);
anim.start();
爲了讓ObjectAnimator能正常地運作,你還需要注意下面幾點:- 要爲對應的對象提供setter方法,如上例中需要爲foo對象添加setAlpha(float value)方法。在不能修改對象源碼的情況下,要不先對對象進行封裝(extends),或者使用ValueAnimator。
- 如果ObjectAnimator的工廠方法中的values... 參數提供了一個值(原本需要提供起始值和結束值),那麼該值會被認爲是結束值。起始值需要通過對象的getter方法提供,因此,在這種情況下,還需要提供對應屬性的getter方法。
ObjectAnimator.ofFloat(targetObject, "propName", 1f)
- 如果動畫的對象是View,那麼就可能需要在
onAnimationUpdate()
回調函數中
調用View.invalidate()方法來刷新屏幕的顯示。比如說,設置Drawable對象的color屬性。但是,View中的所有setter方法,如setAlpha()
andsetTranslationX()會自動地調用invalidate()方法,因此不需要額外地調用invalidate()方法。
使用AnimatorSet編排多個Animator
AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();
上面的代碼片段,動畫的執行順序如下:- 播放bounceAnim動畫
- 同時播放
squashAnim1
,squashAnim2
,stretchAnim1
, andstretchAnim2
- 播放bounceBackAnim
- 播放fadeAnim
Animation監聽器
-
Animator.AnimatorListener
-
onAnimationStart()
- 動畫啓動時調用 -
onAnimationEnd()
- 動畫結束時調用 -
onAnimationRepeat()
- 動畫重新播放時調用 -
onAnimationCancel()
- 動畫被Cancel時調用. 一個被Cancel的動畫也會調用onAnimationEnd()
-
-
ValueAnimator.AnimatorUpdateListener
-
onAnimationUpdate()
- 在動畫的每一幀上調用. 在這個方法中,你可以使用ValueAnimator的getAnimatedValue()方法來獲取計算出來的值。當然,這個監聽器一般只適用於ValueAnimator。值得注意的是,你可能需要在這個方法中調用View.invalidate()方法來刷新屏幕的顯示。
-
AnimatorListenerAdapter來代替對Animator.AnimatorListener的接口的實現,那麼就只需要實現你所關心的方法了。如:
ValueAnimatorAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
balls.remove(((ObjectAnimator)animation).getTarget());
}
動畫在ViewGroup佈局改變時的應用
LayoutTransition
上可以通過調用 setAnimator()方法來設置Animator,另外,還需要向這個方法傳遞一個 LayoutTransition標誌常量,這個常量指示着在什麼時候執行這個animator,可用的常量有:
-
APPEARING
- 指示layout中的view正要顯示的時候運行動畫 -
CHANGE_APPEARING
- 指示layout中因爲有新的view加入而改變layout時運行動畫 -
DISAPPEARING
- 指示layout中的view正要消失的時候運行動畫 -
CHANGE_DISAPPEARING
- 指示layout中有view消失而改變layout時運行動畫
android:animateLayoutchanges
這個屬性設置爲true:<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/verticalContainer"
android:animateLayoutChanges="true" />
自定義Evaluator
IntEvaluator
, FloatEvaluator
,
and ArgbEvaluator
這三種計算器都不能滿足你的要求的時候,你可以通過實現 TypeEvaluator
接口的 evaluate()方法來自定義一個Evaluator。
下面是FloatEvaluator的evaluate()的實現:
public class FloatEvaluator implements TypeEvaluator {
public Object evaluate(float fraction, Object startValue, Object endValue) {
float startFloat = ((Number) startValue).floatValue();
return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
}
}
自定義Interpolator
- 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; }
使用Keyframes方式創建動畫
Keyframe
對象由elapsed
fraction/value對組成。 Keyframe
對象還可以使用插值器。下面是示例: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);
使用ViewPropertyAnimator創建動畫
- 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);
通過XML方式聲明Animator
-
ValueAnimator
-<animator>
-
ObjectAnimator
-<objectAnimator>
-
AnimatorSet
-<set>
<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>
爲了能夠運行上面聲明的animator,必須在代碼中使用AnimatorInflater的inflate方法來實例化xml聲明的animator,如:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
R.anim.property_animator);
set.setTarget(myObject);
set.start();