Android動畫中篇(插值器、估值器)
插值器(Interpolator)&估值器(TypeEvaluator)
插值器(Interpolator)
- 定義:一個介面
- 作用:設定屬性值從初始值過渡到結束值 的變化規律,如勻速、加速 & 減速等等
,即確定了 動畫效果變化的模式,如勻速變化、加速變化等等。 - 應用場景:實現非線性運動的動畫效果
非線性運動:動畫改變的速率不是一成不變的,如加速 & 減速運動都屬於非線性運動
- 在動畫效果的XML程式碼中設定插值器屬性android:interpolator
<?xml version="1.0" encoding="utf-8"?> <!--通過資源ID設定插值器--> <scale xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/overshoot_interpolator" android:duration="3000" android:startOffset="1000" android:fromXScale="0.0" android:toXScale="2" android:fromYScale="0.0" android:toYScale="2" android:pivotX="50%" android:pivotY="50%"> </scale>
- 在 Java 程式碼中設定
Animation scaleAnimation = new ScaleAnimation(0, 2, 0, 2, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); scaleAnimation.setDuration(3000); //scaleAnimation.setInterpolator(MainActivity.this,android.R.anim.overshoot_interpolator); 通過設定資源ID方式實現,等同於下面建立物件方式 //建立對應的插值器類物件 Interpolator overShootInterpolator = new OvershootInterpolator(); //給動畫設定插值器 scaleAnimation.setInterpolator(overShootInterpolator); //播放動畫 button.startAnimation(scaleAnimation);
- 那麼使用插值器時的資源ID是什麼呢?即有哪些型別的插值器可供我們使用呢?下面我們將介紹下系統給我們提供的內建插值器型別。
- 系統內建插值器型別
作用 | 資源ID | 對應的Java類 |
---|---|---|
動畫加速進行 | @android:anim/accelerate_interpolator | AccelerateInterpolator |
快速完成動畫,超出再回到結束樣式 | @android:anim/overshoot_interpolator | OvershootInterpolator |
先加速再減速 | @android:anim/accelerate_decelerate_interpolator | AccelerateDecelerateInterpolator |
先退後再加速前進 | @android:anim/anticipate_interpolator | AnticipateInterpolator |
先退後再加速前進,超出終點後再回終點 | @android:anim/anticipate_overshoot_interpolator | AnticipateOvershootInterpolator |
最後階段彈球效果 | @android:anim/bounce_interpolator | BounceInterpolator |
週期運動 | @android:anim/cycle_interpolator | CycleInterpolator |
減速 | @android:anim/decelerate_interpolator | DecelerateInterpolator |
勻速 | @android:anim/linear_interpolator | LinearInterpolator |
-
使用時:
當在XML檔案設定插值器時,只需傳入對應的插值器資源ID即可
當在Java程式碼設定插值器時,只需傳入對應的插值器資源ID或建立對應的插值器物件即可
系統預設的插值器是AccelerateDecelerateInterpolator,即先加速後減速
-
系統內建插值器的效果圖:
系統內建插值器.gif
- 使用Android內建的插值器能滿足大多數的動畫需求,如果上述9個插值器無法滿足需求,還可以自定義插值器,下面將介紹如何自定義插值器(Interpolator)。
自定義插值器
- 本質:根據動畫的進度(0%-100%)計算出當前屬性值改變的百分比
- 具體使用:自定義插值器需要實現 Interpolator / TimeInterpolator介面 & 複寫getInterpolation()方法
- 補間動畫實現Interpolator介面;屬性動畫一般實現TimeInterpolator介面
- TimeInterpolator介面是屬性動畫中新增的,用於相容Interpolator介面,這使得所有過去的Interpolator實現類也可以直接在屬性動畫使用。
// Interpolator介面 public interface Interpolator { // 內部只有一個方法 /*引數說明: input值值變化範圍是0-1,且隨著動畫進度(0% - 100% )均勻變化; 即動畫開始時,input值 = 0,動畫結束時input = 1; 而中間的值則是隨著動畫的進度(0% - 100%)在0到1之間均勻增加。*/ float getInterpolation(float input) { ...// 插值器的計算邏輯 // 返回的值就是用於估值器繼續計算的fraction值,下面會詳細說明 return xxx; } // TimeInterpolator介面 // 同上 public interface TimeInterpolator { float getInterpolation(float input); }
- 在學習自定義插值器前,我們先來看兩個已經實現好的系統內建差值器:
- 勻速插值器:LinearInterpolator
- 先加速再減速 插值器:AccelerateDecelerateInterpolator
// 勻速差值器:LinearInterpolator @HasNativeInterpolator public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory { // 僅貼出關鍵程式碼 ... public float getInterpolation(float input) { return input; /*沒有對input值進行任何邏輯處理,直接返回 即input值 = fraction值 因為input值是勻速增加的,因此fraction值也是勻速增加的, 所以動畫的運動情況也是勻速的,所以是勻速插值器。*/ } } // 先加速再減速 差值器:AccelerateDecelerateInterpolator @HasNativeInterpolator public class AccelerateDecelerateInterpolator implements Interpolator, NativeInterpolatorFactory { // 僅貼出關鍵程式碼 ... public float getInterpolation(float input) { return (float) (Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; /*input的運算邏輯如下: 使用了餘弦函式,因input的取值範圍是0到1,那麼cos函式中的取值範圍就是π到2π。 而cos(π)的結果是-1,cos(2π)的結果是1 所以該值除以2加上0.5後,getInterpolation()方法最終返回的結果值還是在0到1之間。 只不過經過了餘弦運算之後,最終的結果不再是勻速增加的了,而是經歷了一個先加速後減速的過程 所以最終,fraction值 = 運算後的值 = 先加速後減速,所以該差值器是先加速再減速的。*/ } }
- 從上面看出,自定義插值器的關鍵在於:對input值根據動畫的進度(0%-100%)通過邏輯計算,計算出當前屬性值改變的百分比。
- 下面我將用一個例項來說明該如何自定義插值器
例項
- 目的:寫一個自定義Interpolator,先減速後加速。
-
根據需求實現Interpolator介面
DecelerateAccelerateInterpolator.java
package cn.nascent.com.blog; import android.animation.TimeInterpolator; public class DecelerateAccelerateInterpolator implements TimeInterpolator { @Override public float getInterpolation(float input) { float result; if (input <= 0.5) { // 使用正弦函式來實現先減速後加速的功能,邏輯如下: // 因為正弦函式初始弧度變化值非常大,剛好和餘弦函式是相反的 // 隨著弧度的增加,正弦函式的變化值也會逐漸變小,這樣也就實現了減速的效果。 // 當弧度大於π/2之後,整個過程相反了過來,現在正弦函式的弧度變化值非常小,漸漸隨著弧度繼續增加,變化值越來越大,弧度到π時結束,這樣從0過度到π,也就實現了先減速後加速的效果 result = (float) (Math.sin(Math.PI * input)) / 2; } else { result = (float) (2 - Math.sin(Math.PI * input)) / 2; } // 返回的result值 = 隨著動畫進度呈先減速後加速的變化趨勢 return result; } }
- 建立自定義Interpolator物件並使用
// 獲得當前按鈕的位置 float curTranslationX = button.getTranslationX(); // 建立物件屬性動畫,後面會詳細說明。 /*引數表示的意思是: 動畫作用物件是button 動畫作用的物件的屬性是X軸平移 動畫效果是:從當前位置平移到x=500的位置再平移到初始位置*/ ObjectAnimator animator = ObjectAnimator.ofFloat(button, "translationX", curTranslationX, 500, curTranslationX); animator.setDuration(3000); //建立自定義插值器類物件 TimeInterpolator decelerateAccelerateInterpolator = new DecelerateAccelerateInterpolator(); //給動畫設定自定義插值器 animator.setInterpolator(decelerateAccelerateInterpolator); //播放動畫 animator.start();

自定義插值器.gif
估值器(TypeEvaluator)
- 定義:一個介面
- 作用:設定屬性值從初始值過渡到結束值的變化具體數值
- 插值器(Interpolator)決定值的變化規律(勻速、加速等等),即決定的是變化趨勢;而估值器決定數值的具體變化。
- 屬性動畫特有的屬性。
- 應用場景:配合插值器一起使用,實現非線性運動的動畫效果。
- 具體使用
// 在第4個引數中傳入對應估值器類的物件 ObjectAnimator anim = ObjectAnimator.ofObject(button, "height", new Evaluator(),1,3);
- 系統內建的估值器
IntEvaluator:以整型的形式從初始值 - 結束值 進行過渡
FloatEvaluator:以浮點型的形式從初始值 - 結束值 進行過渡
ArgbEvaluator:以Argb型別的形式從初始值 - 結束值 進行過渡
-
效果圖
IntEvaluator.png
FloatEvaluator.png
- 如果上述內建的估值器無法滿足需求,還可以自定義估值器,下面將介紹如何自定義插值器(Interpolator)。
自定義估值器
- 本質:根據插值器計算出當前屬性值改變的百分比結合初始值和結束值來計算當前屬性具體的數值。
如:動畫進行了50%(初始值=100,結束值=200 ),那麼勻速插值器計算出了當前屬性值改變的百分比是50%,那麼估值器則負責計算當前屬性值 = 100 + (200-100)x50% = 150。
- 具體使用:自定義估值器需要實現 TypeEvaluator介面 & 複寫evaluate()
public interface TypeEvaluator { // 引數說明 // fraction:插值器getInterpolation()方法的返回值 // startValue:動畫的初始值 // endValue:動畫的結束值 public Object evaluate(float fraction, Object startValue, Object endValue) { ....// 估值器的計算邏輯 return xxx; // 賦給動畫屬性具體數值,使用反射機制改變屬性變化 } }
特別注意:
插值器的input值和估值器fraction有什麼關係呢?
答:input的值決定了fraction的值,input值經過計算後傳入到插值器的getInterpolation()方法,然後通過實現getInterpolation()方法中的邏輯演算法,根據input值來計算出一個返回值,而這個返回值就是fraction了。
- 在學習自定義插值器前,我們先來看一個系統內建差值器的實現——浮點型插值器(FloatEvaluator)。
// FloatEvaluator實現了TypeEvaluator介面 public class FloatEvaluator implements TypeEvaluator { // 重寫evaluate() // 引數說明 // fraction:表示動畫完成度(根據它來計算當前動畫的值) // startValue、endValue:動畫的初始值和結束值 public Object evaluate(float fraction, Object startValue, Object endValue) { float startFloat = ((Number) startValue).floatValue(); return startFloat + fraction * (((Number) endValue).floatValue() - startFloat); // 初始值過渡到結束值的演算法是: // 1. 用結束值減去初始值,算出它們之間的差值 // 2. 用上述差值乘以fraction係數 // 3. 再加上初始值,就得到當前動畫的值 } }
- 屬性動畫中的ValueAnimator.ofInt()&ValueAnimator.ofFloat()都具備系統內建的估值器,即FloatEvaluator & IntEvaluator,即系統已經預設實現瞭如何從初始值過渡到結束值的邏輯。
- 但對於ValueAnimator.ofObject(),從上面的工作原理可以看出並沒有系統預設實現,因為對物件的動畫操作複雜 & 多樣,系統無法知道如何從初始物件過度到結束物件。
- 因此,對於ValueAnimator.ofObject(),我們需自定義估值器(TypeEvaluator)來告知系統如何進行從初始物件過渡到結束物件的邏輯。
- 自定義實現的邏輯如下
// 實現TypeEvaluator介面 public class ObjectEvaluator implements TypeEvaluator{ // 複寫evaluate() // 在evaluate()裡寫入物件動畫過渡的邏輯 @Override public Object evaluate(float fraction, Object startValue, Object endValue) { // 引數說明 // fraction:表示動畫完成度(根據它來計算當前動畫的值) // startValue、endValue:動畫的初始值和結束值 ... // 寫入物件動畫過渡的邏輯 // 返回物件動畫過渡的邏輯計算後的值 return value; }
- 例項將在下篇值屬性動畫的ValueAnimator.ofObject中詳細說明。
感謝
ofollow,noindex">Android 動畫:你真的會使用插值器與估值器嗎?(含詳細例項教學)