如何使用TypeEvaluator
如果你想實現一個安卓系統中沒有的動畫類型,你可以通過實現TypeEvaluator接口創建自己的計算實現。在Android系統已實現的類型有int(IntEvaluator),float(FloatEvaluator),或顏色(ArgbEvaluator)。
TypeEvaluator接口中只有一個evaluate()方法需要實現。這個方法會在動畫的當前點返回對應的屬性值。 下面是FloatEvaluator類的實現代碼
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);
}
}
注意:當ValueAnimator(或ObjectAnimator)運行時,它會根據interpolator類計算當前運行部分的動畫的數值(0和1之間),然後計算出具體是哪類插值。插值百分比就是TypeEvaluator接收的部分參數,所以當計算動畫部分時,無需再考慮interpolator。
如何使用Interpolators
Interpolators定義了一個動畫過程中的指定值的計算結果。例如,你可以指定在整個動畫過程中線性發生動畫,即動畫在整個時間內均勻地移動,或者你可以指定在整個動畫過程中發生非線性發生動畫,比如,在動畫的開頭或結尾加速或減速。
在整個動畫系統中Interpolators會得到已經執行的動畫百分比。Interpolators會修改這個百分比以符合它所定義的動畫類型。Android系統在android.view.animation包中提供一組通用的Interpolators實現。如果這些都不符合你的需要,你可以實現 TimeInterpolator接口來創建一個。
下面兩個例子展示了AccelerateDecelerateInterpolator 和LinearInterpolator 是如何計算這個百分比數值的。
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;
}
下表是根據這些計算得來的在1000毫秒內的數據:
經過時間(ms) | 線性(LinearInterpolator) | 非線性(AccelerateDecelerateInterpolator) |
---|---|---|
0 | 0 | 0 |
200 | .2 | .1 |
400 | .4 | .345 |
600 | .6 | .8 |
800 | .8 | .9 |
1000 | 1 | 1 |
如表所示,該LinearInterpolator變化值,以相同的速度,200ms經過0.2。AccelerateDecelerateInterpolator同前面相比在200ms到600ms之間速度較快、600ms到1000ms之間速度較慢。
如何指定關鍵幀
一個關鍵幀的對象由時間/值對組成,你可以在一個動畫的具體時間定義一個特定的狀態。每個關鍵幀也可以有自己的Interpolators控制在一上個關鍵幀和當前關鍵幀時間的動畫行爲。
爲了實例化一個關鍵幀的對象,你必須使用ofint(),offloat() ofobject()這三個工廠方法之一,來對應關鍵幀的類型。然後調用ofkeyframe()工廠方法來獲得一個PropertyValuesHolder對象。一旦你有了以上兩個對象,你就可以使用它們來實現一個動畫效果。示例代碼如下所示
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);
如何對View對象添加屬性動畫
屬性動畫系統在對view添加的動畫是流暢的。視圖動畫系統轉化的視圖對象的改變僅僅是基於視圖的繪製。因爲視圖本身沒有繪製的功能,這種繪製由每個視圖的容器來處理。這導致在視圖動起來的同時,視圖對象本身沒有變化。即使繪製的位置已經同原來位置有所不同。在Android 3.0以後,可以使用屬性動畫和添加對應的setter和getter方法來解決這個問題。
屬性動畫系統可以將屏幕上的視圖通過改變該對象的實際屬性使之動起來。此外,當View對象的屬性發生改變時,它也會自動調用invalidate()方法刷新屏幕。新特性下視圖中的支持動畫的屬性有:
translationX and translationY: 這些屬性控制位於自身容器中以左上角爲頂點的座標
rotation, rotationX, and rotationY: 這些屬性控制二維旋轉(平面)和三維旋轉
scaleX and scaleY: 這些屬性控制二維基於樞軸點的視圖縮放
pivotX and pivotY: 這些屬性控制的樞軸點的位置,適用於旋轉和縮放。默認情況下,樞軸點位於對象的中心
x and y: 這些用來簡單有效的描述位於其容器視圖的最終位置,分別爲left和translationX的和值以及top和translationY的和值
alpha: 視圖透明度,這個值爲1(默認值)時:不透明,爲0時,不可見(全透明)
想針對View的某個屬性添加動畫,比如如顏色或rotation,你只需要創建一個屬性動畫來指定視圖的屬性,例如:
ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);
如何使用ViewPropertyAnimator
ViewPropertyAnimator的提供了一個簡單的方法來同時對一個對象的一些屬性進行修改。它的所做的就像一個ObjectAnimator,因爲它修改View的屬性的實際值,但當同時修改多個屬性時會更有效。此外,使用ViewPropertyAnimator代碼更簡潔也更容易閱讀。下面的代碼片段展示了在使用多個ObjectAnimator對象的不同,一個ObjectAnimator對象,以及ViewPropertyAnimator對視圖的x、y屬性進行修改時候的區別
多個ObjectAnimator
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
一個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中定義屬性動畫
屬性動畫系統允許通過XML定義動畫來替代編碼。通過在XML中定義你的動畫,你可以很容易地在多個頁面和動畫隊列中重用你的動畫。
區分使新的屬性動畫同原有的動畫文件有所區別,從Android 3.1開始,你應該保存XML文件在res/animator/ 目錄下(而不是res/anim/)。animator的名稱是可選的,但首先你得在Eclipse的ADT插件使用layout editor tools (ADT 11.0.0 +版本),因爲ADT只搜索res/animator/目錄下的屬性動畫資源。
下面是屬性動畫類XML支持的XML標籤:
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>
爲了運行這個動畫,你必須使用AnimatorInflater對象來得到一個XML動畫,然後所有動畫開始指定動畫對象。調用 setTarget()即可爲該XML下的所有動畫指定同一個目標。下面的代碼展示瞭如何實現:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
R.anim.property_animator);
set.setTarget(myObject);
set.start();