前言:
上1篇文章傳統(tǒng)View動畫與Property動畫基礎(chǔ)及比較簡單 對Android動畫系統(tǒng)的簡單基礎(chǔ)做了1些比較,本篇文章將對PropertyAnimation進行全面深入的探討,本篇文章可以分為兩大塊,從第6部份可以作為分界點。前5部份側(cè)重講授了PropertyAnim的動畫值的計算進程,ValueAnimator與ObjectAnimator和TimeInterpolation與TypeEvaluator之間的介紹和比較,這幾點是比較重要的,從第6部份開始是通過源碼的角度分析了全部動畫計算和內(nèi)部的處理細(xì)節(jié),和引出了對JakeWharton大神的NineOldAndroids 開源庫的分析,如果你覺得太多,可以分開來看,有理解不準(zhǔn)確的地方,歡迎大家指正。
Duration:動畫的延續(xù)時間
TimeInterpolation: 用于定義動畫變化率的接口,所有插值器都必須實現(xiàn)此接口,如線性,非線性插值器。
TypeEvaluator: 用于定義屬性值計算方式的接口,有int,float,color類型,根據(jù)屬性的起始、結(jié)束值和插值1起計算出當(dāng)前時間的屬性值
Animation sets: 動畫集合,便可以同時對1個對象利用多個動畫,這些動畫可以同時播放也能夠?qū)Σ煌瑒赢嬙O(shè)置不同的延遲
Frame refreash delay: 多少時間刷新1次,即每隔多少時間計算1次屬性值,默許為10ms,終究刷新時間還受系統(tǒng)進程調(diào)度與硬件的影響
Repeat Country and behavoir:重復(fù)次數(shù)與方式,如播放3次、5次、無窮循環(huán),可讓此動畫1直重復(fù),或播放完時向反向播放
1.1 示例
示例1:線性動畫
簡單理解為勻速,下面描寫了1個物體的X屬性的運動。該對象的X坐標(biāo)在40ms內(nèi)從0移動到40 pixel,每10ms刷新1次,移動4次,每次移動40/4=10pixel。
簡單的理解為非勻速,一樣的40pixel,一樣的時間,但是速率不同,開始和結(jié)束的速度要比中間部份慢,即先加速后減速
1.2、屬性動畫的幾個重要組成部份
TimeInterpolator 實現(xiàn)插值器的接口,用于計算插值。
TypeAnimator 計算屬性值的接口。
ValueAnimator 已實現(xiàn)了TimeInterpolator和TypeAnimator接口,跟蹤了動畫時間的相干屬性,比如1個動畫已完成了多長時間,當(dāng)前履行動畫的開始、結(jié)束或?qū)傩灾怠?
1.3、動畫的計算進程
進程1:計算已完成動畫分?jǐn)?shù) elapsed fraction
為了履行1個動畫,你需要創(chuàng)建1個ValueAnimator,并且指定目標(biāo)對象屬性的開始、結(jié)束值和延續(xù)時間。在調(diào)用start后,全部動畫進程中, ValueAnimator會根據(jù)已完成的動畫時間計算得到1個0到1之間的分?jǐn)?shù),代表該動畫的已完成動畫百分比。0表示0%,1表示100%,比如,示例1中,總時間 t = 40 ms,t = 10 ms 的時候是 0.25。
進程2:計算插值(動畫變化率)interpolated fraction
當(dāng)ValueAnimator計算完已完成動畫分?jǐn)?shù)后,它會調(diào)用當(dāng)前設(shè)置的TimeInterpolator,去計算得到1個interpolated(插值)分?jǐn)?shù),在計算進程中,已完成動畫百分比會被加入到新的插值計算中。如示例2中,由于動畫的運動是緩慢加速的,它的插值分?jǐn)?shù)大約是 0.15,小于在 t = 10ms 時的已完成動畫分?jǐn)?shù)0.25。而在示例1中,這個插值分?jǐn)?shù)1直和已完成動畫分?jǐn)?shù)是相同的。
關(guān)于插值器的詳細(xì)介紹,可以看2.3節(jié)。
進程3:計算屬性值
當(dāng)插值分?jǐn)?shù)計算完成后,ValueAnimator 會根據(jù)插值分?jǐn)?shù)調(diào)用適合的 TypeEvaluator去計算運動中的屬性值。
以上分析引入了兩個概念:已完成動畫分?jǐn)?shù)(elapsed fraction)、插值分?jǐn)?shù)( interpolated fraction )。
在上面的示例2中,TimeInterpolator 使用的是 AccelerateDecelerateInterpolator ,而它的TypeEvaluator使用的是 IntEvaluator。
明白具體的進程后,我們來分析1下它的計算進程,取 t = 10ms:
進程1:計算已完成動畫時間分?jǐn)?shù):t=10ms/40ms=0.25.
進程2:由于上述例子中用了AccelerateDecelerateInterpolator,其計算公式以下(input即為時間因子),經(jīng)計算得到的插值大約為0.15:
這里簡單說下,Interpolator接口的直接繼承自TimeInterpolator,內(nèi)部沒有任何方法,而TimeInterpolator只有1個getInterpolation方法,所以所有的Interpolator只需實現(xiàn)getInterpolation方法便可。下面是AccelerateDecelerateInterpolator的源碼:
參數(shù)分別為上1步的插值分?jǐn)?shù)、起始值、結(jié)束值。
相信大家看到這里,全部動畫的計算進程應(yīng)當(dāng)是非常清楚了。
第6部份的源碼分析詳細(xì)的介紹了這3個進程的內(nèi)部實現(xiàn)。
由于View Animation 系統(tǒng)已在android.view.animation中定義了很多的插值器,你可以直接利用到你的屬性動畫中。 Animator雖然提供了創(chuàng)建動畫的基本框架,但你不應(yīng)當(dāng)直接使用這個類,由于它只提供了很少的功能,需要去擴大才能完全支持動畫。下面介紹的是1些屬性動畫系統(tǒng)中的主要類。
1.ValueAnimator
屬性動畫中的主要的時序引擎,如動畫時間,開始、結(jié)束屬性值,相應(yīng)時間屬性值計算方法等。包括了所有計算動畫值的核心函數(shù)。也包括了每個動畫時間上的細(xì)節(jié),信息,1個動畫是不是重復(fù),是不是監(jiān)聽更新事件等,并且還可以設(shè)置自定義的計算類型。
全部Property Animation動畫有兩個步聚:
1.計算屬性值
ValueAnimiator只完成了第1步工作,如果要完成第2步,你必須監(jiān)聽由ValueAnimator計算得到的屬性值,并修改目標(biāo)對象。需要實現(xiàn)ValueAnimator .onUpdateListener 接口,自己去處理對象的動畫邏輯,比如:
2.ObjectAnimator
繼承自ValueAnimator,允許你指定要進行動畫的對象和該對象的1個屬性。該類會根據(jù)計算得到的新值自動更新屬性。也就是說上Property Animation的兩個步驟都實現(xiàn)了。大多數(shù)的情況,你使用ObjectAnimator就足夠了,由于它使得目標(biāo)對象動畫值的處理進程變得簡單,不用再向ValueAnimator那樣自己寫動畫更新的邏輯。但ObjectAnimator有1定的限制,比如它需要目標(biāo)對象的屬性提供指定的處理方法,這個時候你需要根據(jù)自己的需求在ObjectAnimator和ValueAnimator中做個選擇了,看哪一種實現(xiàn)更簡便。在下面的第3部份有重點介紹。
3.AnimationSet
動畫集合,提供了1個把多個動畫組合成1個組合的機制,并可設(shè)置組中動畫的時序關(guān)系,猶如時播放、順序播放或延遲播放。Elevator會告知屬性動畫系統(tǒng)如何計算1個屬性的值,它們會從Animator類中獲得時序數(shù)據(jù),比如開始和結(jié)束值,并根據(jù)這些數(shù)據(jù)計算動畫的屬性值。
4.TimeAnimator
它其實不能直接實現(xiàn)動畫效果,它是1個對監(jiān)聽者的簡單回調(diào)機制,在TimeListener接口的onTimeUpdate回調(diào)方法中返回動畫延續(xù)的時間與上次調(diào)用的間隔時間,沒有duration、interpolation和設(shè)置值的方法等。主要是在動畫的每幀的時候Notify其監(jiān)聽者做相應(yīng)的處理。
更詳細(xì)的分析和在實際使用中如何選擇,請參考第3部份。
2.2 Evaluators
Evaluators 告知屬性動畫系統(tǒng)如何去計算1個屬性值。它們通過Animator提供的動畫的起始和結(jié)束值去計算1個動畫的屬性值。
屬性系統(tǒng)提供了以下幾種Evaluators:
1.IntEvaluator
2.FloatEvaluator
3.ArgbEvaluator
這3個由系統(tǒng)提供,分別用于計算int,float,color型(106進制)屬性的計算器
4.TypeEvaluator
1個用于用戶自定義計算器的接口,如果你的對象屬性值類型,不是int,float,或color類型,你必須實現(xiàn)這個接口,去定義自己的數(shù)據(jù)類型。
更詳細(xì)的介紹,請參考第5部份:使用TypeEvaluator
插值器:時間的函數(shù),定義了動畫的變化律。
插值器只需實現(xiàn)1個方法:getInterpolation(float input),其作用就是把0到1的elapsed fraction變化映照到另外一個interpolated fraction。傳入?yún)?shù)是正常履行動畫的時間點,返回值是用戶真正想要它履行的時間點。傳入?yún)?shù)是{0,1},返回值1般也是{0,1}。{0,1}表示整段動畫的進程。中間的0.2、0.3等小數(shù)表示在全部動畫(本來是勻速的)中的位置,其實就是1個比值。如果返回值是負(fù)數(shù),會沿著相反的方向履行。如果返回的是大于1,會超越正方向履行。也就是說,動畫可能在你指定的值上下波動,大多數(shù)情況下是在指定值的范圍內(nèi)。
getInterpolation(float input)改變了默許動畫的時間點elapsed fraction,根據(jù)時間點interpolated fraction得到的是與默許時間點不同的屬性值,插值器的原理就是通過改變實際履行動畫的時間點,提早或延遲默許動畫的時間點來到達加速/減速的效果。動畫插值器目前都只是對動畫履行進程的時間進行修飾,并沒有對軌跡進行修飾。
簡單點解釋這個方法,就是當(dāng)要履行input的時間時,通過Interpolator計算返回另外1個時間點,讓系統(tǒng)履行另外1個時間的動畫效果。
經(jīng)過動畫計算進程的第1步,會獲得1個已完成時間百分比elapsed fraction,也就是getInterpolation方法的參數(shù)input。插值器,就是時間的函數(shù),插值就是函數(shù)值。Android動畫提供的AccelerateDecelerateInterolator的源碼為:
截圖來自:http://cogitolearning.co.uk/?p=1078,該文章也有關(guān)于Android Property Anim的介紹,有興趣的可以看1下。
![]()
下面我們再通過AccelerateDecelerate的函數(shù)圖來進1步分析。
該曲線圖,表現(xiàn)了動畫計算的兩個進程:X軸是時間因子(正好最大值為1,那末每一個X軸上的值就能夠看作是百分比),也就是動畫計算進程的第1步所得到的值,Y軸就是相應(yīng)時間的插值,就是動畫計算進程的第2步。還有1步,這里沒有體現(xiàn)出來,就是通過TypeEvaluator計算終究的屬性值。
下面介紹幾種插值器:
AccelerateDecelerateInterolator 先加速后減速,開始結(jié)束時慢,中間加速
AccelerateInterpolator 加速,開始時慢中間加速
DecelerateInterpolator 減速,開始時快然后減速
AnticipateInterpolator 反向 ,先向相反方向改變1段再加速播放
AnticipateOvershootInterpolator 反向加超出,先向相反方向改變,再加速播放,會超越目的值然后緩慢移動至目的值
BounceInterpolator 跳躍,快到目的值時值會跳躍,如目的值100,后面的值可能順次為85,77,70,80,90,100
CycleIinterpolator 循環(huán),動畫循環(huán)1定次數(shù),值的改變成1正弦函數(shù):Math.sin(2 * mCycles * Math.PI * input)
LinearInterpolator 線性,線性均勻改變
OvershottInterpolator 超出,最后超越目的值然后緩慢改變到目的值
TimeInterpolator 1個接口,允許你自定義interpolator,以上幾個都是實現(xiàn)了這個接口
如果這些插值器不能滿足你的需求,那末你可以通過實現(xiàn)TimeInterpolator接口去創(chuàng)建自己的插值器。下面是 LinearInterpolator計算插值的方法,LinearInterpolator(線性插值器)對已完成動畫百分比沒有影響。
LinearInterpolator
3、利用動畫
ValueAnimator類可以為1些動畫指定1系列的int,float,color值。通過調(diào)用工廠方法ofInt(),ofFloat().ofObject()來獲得1個ValueAnimator.
上面這段是無效的代碼,由于這里根本就沒有動畫目標(biāo)的影子,也沒有在ValueAnimator的監(jiān)聽中獲得計算得到的屬性值去更新目標(biāo)對象,所以不會有動畫效果。
你需要為動畫指定1個自定義的類型:
ValueAnimator通過MyTypeEvalutor提供的邏輯去計算1個時長為1000ms的動畫在開始和結(jié)束之間的屬性值,從start方法開始算起。第1塊代碼,對對象沒有起到真實的效果,你通常希望通過計算得到的屬性值去修改動畫對象,但這里的ValueAnimator沒有直接操作1個對象或?qū)傩?。你需要在ValueAnimator中實現(xiàn)1個AnimatorUpdateListener監(jiān)聽去手動更新目標(biāo)對象的屬性值和處理動畫生命周期中的其它重要事件,如frame的更新。當(dāng)你實現(xiàn)了監(jiān)聽以后,你可以通過getAnimateValue()方法獲得某1幀的動畫值,然后做更新操作。更多關(guān)于Listeners的介紹,你可以參考第4部份:Animation Listeners
更加簡便,動畫屬性會自動更新,不用再像ValueAnimator那樣自己去實現(xiàn)更新的動畫邏輯,但需要遵守1定的規(guī)則。
ObjectAnimator是ValueAnimator的子類,并且同時具有時序引擎和屬性值計算和自動更新屬性值的功能,使得為對象添加動畫變得更加簡單。因此你不再需要去實現(xiàn)ValueAnimator.AnimatorUpdateListener去更新動畫的屬性了。
ObjectAnimator的自動更新功能,依賴于屬性身上的setter和getter方法,所以為了讓ObjectAnimator能夠正確的更新屬性值,你必須遵從以下規(guī)范:
c.使用ValueAnimator代替。
2. 如果你為ObjectAnimator的工廠方法的可變參數(shù)只傳遞了1個值,那末會被作為動畫的結(jié)束值。因此,你的目標(biāo)對象屬性上必須要有1個getter方法,用于獲得動畫的起始值。這個獲得方法必須使用get()的格式。例如,屬性是foo,就必須有1個getFoo方法。
targetObject.setPropName(float) 和targetObject.getPropName(float) :
4. 根據(jù)動畫的目標(biāo)屬性或?qū)ο蟛煌?,你可能需要調(diào)用某個View的invalidate方法,根據(jù)新的動畫值去強迫屏幕重繪該View??梢栽趏nAnimateonUpdate()回調(diào)方法中去做。比如,對1個Drawable的色彩屬性進行動畫,只有當(dāng)對象重繪本身的時候,才會致使該屬性的更新,(不像平移或縮放那樣是實時的)。1個VIew的所有setter屬性方法,比如setAlpha()和setTranslationX()都可以適當(dāng)?shù)母耉iew。因此你不需要在重繪的時候為這些方法傳遞新的值。更多關(guān)于 Listener的信息,可以參考第4部份Animation Listeners。
簡單總結(jié)下:
當(dāng)你不希望向外暴露Setter方法的時候,或希望獲得到動畫值統(tǒng)1做處理的話,亦或只需要1個簡單的時序機制的話,那末你可以選擇使用ValueAnimator,它更簡單。
如果你就是希望更新動畫,更簡便的,可使用ObjectAnimator,但你必須有setter和getter方法,并且它們必須都是標(biāo)準(zhǔn)的駝峰式(確保內(nèi)部能夠調(diào)用),必須有結(jié)束值。
根據(jù)需要,不需實時更新的動畫,需要你自己去強迫更新。
很多時候,你需要在1個動畫的開始或結(jié)束點去播放另外一個動畫,Android系統(tǒng)允許你綁定多個動畫到1個AnimatorSet中,因此你可以指定這些動畫是不是同時啟動或有序或延遲進行。你也能夠相互內(nèi)嵌AnimatorSet。下面的代碼來自Google Sample彈力球Sample,按順序播放了以下動畫:
1、播放 bounceAnim.
2、同時播放 squashAnim1, squashAnim2, stretchAnim1, and stretchAnim2
3、播放 bounceBackAnim.
更多細(xì)節(jié),你可以參考APIDemo,APIDemo在大家的SDK中都有,直接導(dǎo)入便可。
你可以通過以下監(jiān)聽器監(jiān)聽動畫進程中的重要事件:
Animator.AnimatorListener
onAnimationStart() - 動畫啟動時的回調(diào)
onAnimationEnd() -動畫結(jié)束時的回調(diào)
onAnimationRepeat() - 動畫重復(fù)本身時候回調(diào)
onAnimationCancel() - 動畫被取消的時候回調(diào),1個動畫取消的時候也會調(diào)用onAnimationEnd方法,而不斟酌動畫是如何結(jié)束的。
onAnimationUpdate() :動畫的每幀都會調(diào)用該方法,監(jiān)聽該事件去使用ValueAnimator計算得到的值。通過getAnimatedValue方法可以獲得當(dāng)前的動畫值。如果你使用 的是ValueAnimator,實現(xiàn)該監(jiān)聽就是有必要的了。
根據(jù)動畫的屬性的實際情況,你可能需要根據(jù)新的動畫值去調(diào)用某個View身上的invalidate方法去強迫刷新某1個區(qū)域。這1點和ObjectAnimator中的第4點相同。
如果你不想實現(xiàn)Animator.AnimatorListener接口的所有的方法,你可以繼承AnimatorListenerAdapter類,而不用去實現(xiàn)Animator.AnimatorListener接口。
AnimatorListenerAdapter類提供了1些空的實現(xiàn),你可以選擇性的覆蓋。比如API中彈力球sample,創(chuàng)建了1個AnimatorListenerAdapter,而只實現(xiàn)了onAnimationEnd方法。
如果你想添加1種動畫系統(tǒng)中沒有的計算類型,就需要自己通過實現(xiàn)TypeEvaluator接口去創(chuàng)建自己的evaluator。Android系統(tǒng)可以辨認(rèn)的類型是:int,float或color。對應(yīng)的java類分別為 IntEvaluator、 FloatEvaluator、 ArgbEvaluator 。
我們再來看1下IntEvaluators的源碼:
大家可以看到,3種計算器都是線性的,且情勢都為: result = x0 + t * (v1 - v0)。
如果你的數(shù)據(jù)類型不是float,int,或color類型,那末你就需要自己實現(xiàn)TypeEvaluator,并實現(xiàn)evaluate方法,根據(jù)自己的數(shù)據(jù)結(jié)構(gòu)計算屬性值。
代碼家的開源動畫庫AnimationEasingFunctions就是根據(jù)1個函數(shù)庫http://easings.net/zh-cn做出來的,每一個不同的動畫效果就是復(fù)寫了evaluate方法,依照不同的函數(shù)計算屬性值,從而到達了相應(yīng)的動畫效果。大家可以自己去看AnimationEasingFunctions的源碼,在理解了1.3動畫的計算進程后,再去看,就非常清晰了,關(guān)鍵地方就是這個evaluate方法根據(jù)不同的函數(shù)做了處理。
TimeInterpolator和TypeEvaluator的區(qū)分
不知道大家弄明白TypeEvaluator和TimeInterpolator沒有,反正當(dāng)時我剛看的時候,有些迷糊,不知道該如何具體的使用。
當(dāng)時分析了代碼家的AnimationEasingFunctions開源項目,發(fā)現(xiàn)它都是在TypeEvaluator中定義函數(shù),而不是在TimeInterpolator中。
我當(dāng)時很困惑,我的想法是在TimeInterpolator 中定義插值函數(shù),而在Evaluators的evaluate方法只是簡單的處理。比如系統(tǒng)提供的Evaluators那樣,簡單的進行線性運算便可,我當(dāng)時對Evaluators的理解是:它只是為了擴大1種數(shù)據(jù)類型,比如系統(tǒng)提供的IntEvaluator、FloatEvaluator,它們內(nèi)部計算只是簡單的線性計算,只是類型不同而已。后來實在不太明白,就向代碼家請教了下,代碼家的答復(fù):
TypeEvalutor的evaluate方法接收的fraction究竟來自于哪里?
我覺得這個fraction非常重要,由于它連接了動畫值計算的第2步和第3步,所以弄清楚它究竟是甚么,對后續(xù)第3步屬性值的計算非常重要。這里也在同1封郵件中向代碼家請教過,代碼家的答復(fù)是從第1個參數(shù)就是從 getInterpolator得到的。但是自己1直覺得哪里不對,后來經(jīng)過Debug得出來了1些結(jié)果,也就是第6部份的來由,如果當(dāng)初沒有深入探索下去,就沒有第6部份源碼分析這1塊,而終究收獲很多,并且弄清了NineOldAndroids的實現(xiàn)原理。
首先說明下,在測試的時候,使用的是ObjectAnimator.ofFloat( )工廠方法,值類型為Float,所之內(nèi)部邏輯使用了FloatKeyframeSet類(關(guān)于FloatKeyframeSet后面有詳細(xì)的介紹,這里只需知道在該類里肯定了傳入Evaluator的fraction)的getFloatValue方法,動畫的每幀都會履行這個方法,這里也是動畫計算進程的第3步產(chǎn)生的地方,先計算得到1個中間值,然后傳遞到evaluator中的evaluate方法中去計算得到終究的屬性值。該方法中,對不同參數(shù)個數(shù)的情況進行了不同的處理,具體看源碼:
FloatKeyframeSet.java
可以看到這里1共處理了4種情況:
mKeyframeNums == 2
fraction <= 0
fraction >= 1
fraction在(0,1)之間且mKeyframeNums != 2
我們先看看keyframe.getFraction()獲得到的是甚么值:
PropertyViewHolder
這里有個從角標(biāo)1開始的for循環(huán),循環(huán)調(diào)用Keyframe.ofFloat(fraction,value)工廠方法,創(chuàng)建Keyframe。第1個keyframe的fraction為0,這是默許的。
而其它關(guān)鍵幀fraction的計算方式我們可以看到:i / (numKeyframes⑴), numKeyframes為用戶傳入到ObjectAnimator.ofFloat(Object target ,String PropertyName,float ...values) 方法的可變參數(shù)values個數(shù)。注意我們這里的value參數(shù)是動畫運動的關(guān)鍵幀,和之前所說的動畫運動的每幀是不同的。運動進程中的每幀是關(guān)鍵幀之間的那1部份,這部份是實時的,而關(guān)鍵幀就是1個個用戶指定的屬性值,希望在某個時間點(上述已計算完成),到達的屬性值。
mKeyframeNums = 2
返回的就是直接從參數(shù)中獲得到的fraction,而這個fraction就是從通過ValueAnimator的Interpolator獲得到的。所以在這類情況下,正如代碼家的回復(fù)1樣。
下面我們看1下源碼中對getInterpolation()方法的注釋:Value可以大于1或小于0。
其實當(dāng)初分析的時候,有1個誤區(qū),就是我所認(rèn)為的evaluate中的fraction必須是[0,1]范圍內(nèi)的1個值,這樣才合適作為1個比例值,所以對getInterpolation(input)方法返回的值,在mKeyframeNums = 2 的時候,直接傳遞給Evaluator的evaluate方法,1直很困惑,最后才明白,getInterpolation(input)的值,其實不受束縛的,完全可以由你自定義的插值函數(shù)來控制,終究計算得到的屬性值,也不1定就比用戶傳入到ofFloat()中的Value小。事實確切是這樣,動畫的運動軌跡,是可以在你的指定的屬性值上下波動的。
我們再看其它3種情況的處理:
fraction <= 0 和 fraction >= 1的情況相似,都是獲得相鄰兩關(guān)鍵幀進行處理,但是它們選擇的兩關(guān)鍵幀是固定的,我個人認(rèn)為這樣的選擇是為了更接近fraction。
假定用戶傳入的values 為 50,100,200,則numKeyframs = 3,那末創(chuàng)建出相應(yīng)的Keyframe為:
Keyframe(0,50),Keyframe(1/2,100),Keyframe(1,200)
intervalFraction就是要傳入Evaluator的evaluate方法的fraction。
fraction <= 0
選擇的是第1幀(從上面的賦值來知道,第1幀的fraction為固定值0)和第2幀
prevkeyframeFraction = 0,nextKeyframeFraction = 1 / 2:
fraction >= 1
由mNumkeyframes⑴,mNumkeyframes⑵,可以知道,這里獲得的就是倒數(shù)第1幀和倒數(shù)第2幀。
prevkeyframeFraction = 1/2 ,nextKeyframeFraction = 1:
mKeyframeNums != 2(或==1,內(nèi)部已處理為2)且在[0,1]范圍內(nèi)
上面邏輯中有這么1行代碼: if (fraction < nextKeyframe.getFraction()) {...}
那末我們可以知道,這個elapsed fraction是某兩關(guān)鍵幀區(qū)間的elapsed fraction,落到了某1關(guān)鍵幀和下1關(guān)鍵幀區(qū)間里。如圖該fraction落在了1/2和1之間的區(qū)域:
上面更加清晰的知道,fraction其實不1定在{0,1}內(nèi),也多是該區(qū)間外的1個值,只是系統(tǒng)為了更接近這個fraction,在做處理的時候,選擇兩個相近的fraction進行計算,得到1個internalFraction傳遞給Evaluator的evaluate方法去計算屬性值。
因此這里可以解決我上面疑問了,evaluate接受的fraction分為兩種:
當(dāng)用戶傳入的屬性值是2個的時候:是getInterpolator()返回的fraction。
其它情況又分為3種,fraction>=1 和 fraction<=1的取值是固定的兩關(guān)鍵幀,0
兜了1大圈,其實就是為了弄清楚這個fraction究竟是個甚么值,現(xiàn)在明白了,其實只要知道這個fraction不1定是{0,1}之間的值,就OK了,就沒有甚么疑問了。
小結(jié):
TypeEvaluator: 定義了屬性值的計算方式,有int,float,color類型,根據(jù)屬性的開始、結(jié)束值和插值1起計算出當(dāng)前時間的屬性值,終極方法,全部計算進程的結(jié)尾。
TimeInterpolation: 插值器都必須實現(xiàn)的接口,定義了動畫的變化率,如線性,非線性。
ValueAnimator與ObjectAnimator:二者都可以進行屬性動畫,但是ObjectAnimator更加簡單,不用去做更新屬性值的計算,但是必須要提供標(biāo)準(zhǔn)的setter和getter方法,讓ObjectAnimator能夠獲得到屬性值。
以上部份為PropertyAnim的核心部份,主要分析已介紹完了,如果1時消化不了,可以將源碼的分析先放1放,回過頭來再看,也沒問題,如果你希望1氣呵成,1下看完自然是極好的 :)
6、通過源碼的角度來分析全部動畫的全進程
先說明1下全部進程的分析是基于Jake Wharton的NineOldAndroids的,但除初始化和動畫的更新不同,其它的整體邏輯和思路是1樣的,只是有些細(xì)節(jié)實現(xiàn)不同,畢竟大神不可能完全copy過來,有自己的代碼習(xí)慣。所以大家不用擔(dān)心和Android系統(tǒng)的源碼有太大出入,而對NineOldAndroids的原理分析部份,側(cè)重談到了實現(xiàn)原理和初始化和動畫更新部份與系統(tǒng)動畫的不同的地方。
初始化進程,就是由ObjectAnimator.ofFloat();方法開始所做的1系列工作
上一篇 使用jqueryUI插件,easyui-datagrid,列表顯示加載兩次
下一篇 windows驅(qū)動完整卸載的流程(解決卸載后,重新掃描或重啟后,驅(qū)動仍然出現(xiàn)的問題)