1. 程式人生 > >當數學遇上動畫(3)

當數學遇上動畫(3)

當數學遇上動畫:講述 ValueAnimator、TypeEvaluator和TimeInterpolator之間的恩恩怨怨(3)

上一節我們得到一個重要的結論,藉助TimeInterpolator或者TypeEvaluator“單獨” 來控制動畫所產生的動畫效果殊途同歸!

此外,上一節結尾我們還說到,專案AnimationEasingFunctions和專案EaseInterpolator本質上是差不多的,都是定義了一些動畫效果對應的函式曲線。前者是將其封裝成了TypeEvaluator,後者是將其封裝成了Interpolator

這一節我們來研究下這些函式曲線。

1 緩動函式曲線

下圖顯示了常見的這些函式曲線,到底這些函式曲線都是什麼鬼呢?

img

這些函式曲線最早是由Robert Penner提出來用於實現補間動畫的"Penner easing functions",這些曲線主要分成10類,包括"BACK", "BOUNCE", "CIRCULAR", "ELASTIC", "EXPO", "QUAD", "CUBIC", "QUART", "QUINT", "SINE",每一類下面都有緩動進入、緩動退出以及緩動進入和退出三種效果,所以共有30個。這些效果對照著函式曲線來看其實也挺好理解,"QUAD", "CUBIC", "QUART", "QUINT"分別對應著二次、三次、四次以及五次曲線,"SINE"對應正弦函式曲線,"EXPO"對應指數函式曲線等等。其中"BACK"

"ELASTIC"有上衝和下衝的效果。

這些版本的實現都是4個引數的,分別是起始值b、數值間隔c(結束值-起始值)、當前時間t、時間間隔d

Java
12345678910111213141516171819202122232425 //不帶緩動,也就是前面說的“線性”估值器functionnoEasing(t,b,c,d){returnc*(t/d)+b;}//帶緩動效果,例如二次曲線形式easeInQuad:function(t,b,c,d){//緩動進入returnc*(t/=d)*t+b;},easeOutQuad:function(t,b,c,d){//緩動退出return-c*(t/=d)*(t-2)+b;},easeInOutQuad:function(t,b,c,d){//緩動進入和退出if((t/=d/2)<1)returnc/2*t*t+b;return-c/2*((--t)*(t-2)-1)+b;},那為什麼與之殊途同歸的EaseInterpolator1個引數的呢?//QuadInOut InterpolatorpublicfloatgetInterpolation(floatinput){if((input/=0.5f)<1){return0.5f*input*input;}return-0.5f*((--input)*(input-2)-1);}

這是因為當Interpolator傳入到後面的TypeEvaluator的時候就有了起始值、結束值以及時間間隔(時間間隔定義在緩動函式內部,只有部分緩動函式需要這個引數)這3個引數,可以參考下面的程式碼來理解,所以說,它們在本質上還是一樣的!

Java
12 fraction=getInterpolation(input)==>這種1個引數形式其實也可以等效於easingfunction(currentTime,0,1,totalTime)value=evaluate(fraction,startValue,endValue)=startValue+fraction*(endValue-startValue)

2 One more thing

看到這裡的話,我們就會想啦,如果我們把函式曲線抽象出來,然後再提供相應的轉換方法,使其輕輕鬆鬆地轉換成InterpolatorTypeEvaluator的話,如此,豈不善哉?

所以,我就站在眾多巨人們的肩膀上,寫了一個新專案Yava,專案程式碼非常簡單,而且程式碼很少只有4個重要的類,它實現的功能就是將抽象的函式曲線輕鬆轉換成立即可用的InterpolatorTypeEvaluator,並且提供了常見的30個緩動函式(Easing Functions)的實現,它們既可以當做Interpolator來用,又可以當做TypeEvaluator來用,非常方便。

這裡我直接把這4個重要類的程式碼貼出來吧。

(1) IFunction介面

Java
123456 /** * 函式介面:給定輸入,得到輸出 */publicinterfaceIFunction{floatgetValue(floatinput);}

(2)AbstractFunction抽象類

Java
123456789101112131415 /** * 抽象函式實現,既可以當做簡單函式使用,也可以當做Interpolator或者TypeEvaluator去用於製作動畫 */publicabstractclassAbstractFunction implementsIFunction,Interpolator,TypeEvaluator<Float>{@OverridepublicfloatgetInterpolation(floatinput){returngetValue(input);}@OverridepublicFloatevaluate(floatfraction,FloatstartValue,FloatendValue){returnstartValue+getValue(fraction)*(endValue-startValue);}}

(3)Functions

Java
1234567891011121314 /** * 工具類,將自定義的函式快速封裝成AbstractFunction */classFunctions{publicstaticAbstractFunction with(finalIFunction function){returnnewAbstractFunction(){@OverridepublicfloatgetValue(floatinput){returnfunction.getValue(input);}};}}

(4)EasingFunction列舉:包含了30個常見的緩動函式

Java
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162 /** * 常見的30個緩動函式的實現 */publicenumEasingFunction implementsIFunction,Interpolator,TypeEvaluator<Float>{/* ------------------------------------------------------------------------------------------- *//* BACK    /* ------------------------------------------------------------------------------------------- */BACK_IN{@OverridepublicfloatgetValue(floatinput){returninput*input*((1.70158f+1)*input-1.70158f);}},BACK_OUT{@OverridepublicfloatgetValue(floatinput){return((input=input-1)*input*((1.70158f+1)*input+1.70158f)+1);}},BACK_INOUT{@OverridepublicfloatgetValue(floatinput){floats=1.70158f;if((input*=2)<1){return0.5f*(input*input*(((s*=(1.525f))+1)*input-s));}return0.5f*((input-=2)*input*(((s*=(1.525f))+1)*input+s)+2);}},//other easing functions ......//如果這個function在求值的時候需要duration作為引數的話,那麼可以通過setDuration來設定,否則使用預設值privatefloatduration=1000f;//目前只有ELASTIC***這三個是需要duration的,其他的都不需要publicfloatgetDuration(){returnduration;}publicEasingFunction setDuration(floatduration){this.duration=duration;returnthis;}//將Function當做Interpolator使用,預設的實現,不需要列舉元素去重新實現@OverridepublicfloatgetInterpolation(floatinput){returngetValue(input);}//將Function當做TypeEvaluator使用,預設的實現,不需要列舉元素去重新實現@OverridepublicFloatevaluate(floatfraction,FloatstartValue,FloatendValue){returnstartValue+getValue(fraction)*(endValue-startValue);}//幾個數學常量publicstaticfinalfloatPI=(float)Math.PI;publicstaticfloatTWO_PI=PI*2.0f;publicstaticfloatHALF_PI=PI*0.5f;}

這個專案的緩動函式的實現參考自EaseInterpolator中的實現,但是這個專案的程式碼和EaseInterpolator以及AnimationEasingFunctions這兩個專案都完全不一樣,非常簡單易懂,既保留了原有專案應有的功能,同時為專案的使用場景提供了更多的可能,任何你想使用Interpolator或者TypeEvaluator都能使用它。

舉個例子,以上一節中的彈跳動畫效果為例,現在可以直接使用EasingFunction.BOUNCE_OUT作為Interpolator或者TypeEvaluator來使用:

第一種方式:使用線性插值器和自定義的TypeEvaluator

Java
12345678 ObjectAnimator animator1=newObjectAnimator();animator1.setTarget(textView1);animator1.setPropertyName("translationY");animator1.setFloatValues(0f,-100f);animator1.setDuration(1000);animator1.setInterpolator(newLinearInterpolator()