日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內(nèi)最全IT社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > php開源 > 綜合技術(shù) > Property Anim詳解

Property Anim詳解

來源:程序員人生   發(fā)布時間:2014-12-13 08:44:41 閱讀次數(shù):7844次

前言:

上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)確的地方,歡迎大家指正。


Property Animation

官方說了Property Animation是1個很強勁的動畫框架,幾近可以為所有的事物加上動畫效果。你可以定義1個動畫去改變?nèi)魏螌ο蟮膶傩?,不管該對象是不是在屏幕上,都可以進行繪制。1個屬性動畫在某1個時間段,改變的是1個對象的1個屬性值(1個對象的1個字段)。

屬性動畫系統(tǒng)為動畫供了以下屬性:

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、Property Animation的工作方式


1.1 示例


示例1:線性動畫


簡單理解為勻速,下面描寫了1個物體的X屬性的運動。該對象的X坐標(biāo)在40ms內(nèi)從0移動到40 pixel,每10ms刷新1次,移動4次,每次移動40/4=10pixel。


示例2:非線性動畫


簡單的理解為非勻速,一樣的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:

public float getInterpolation(float input) { return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; }

這里簡單說下,Interpolator接口的直接繼承自TimeInterpolator,內(nèi)部沒有任何方法,而TimeInterpolator只有1個getInterpolation方法,所以所有的Interpolator只需實現(xiàn)getInterpolation方法便可。下面是AccelerateDecelerateInterpolator的源碼:

public class AccelerateDecelerateInterpolator implements Interpolator { public AccelerateDecelerateInterpolator() { } @SuppressWarnings({"UnusedDeclaration"}) public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) { } public float getInterpolation(float input) { return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; } }

進程3:由于它的TypeEvaluator類型為FloatEvaluator,計算公式以下,由于startValue = 0,所以經(jīng)計算得到屬性值:0.15*(40-0)= 6 pixel:
public Float evaluate(float fraction, Number startValue, Number endValue) { float startFloat = startValue.floatValue(); return startFloat + fraction * (endValue.floatValue() - startFloat); }

參數(shù)分別為上1步的插值分?jǐn)?shù)、起始值、結(jié)束值。

相信大家看到這里,全部動畫的計算進程應(yīng)當(dāng)是非常清楚了。

第6部份的源碼分析詳細(xì)的介紹了這3個進程的內(nèi)部實現(xiàn)。


2、相干對象的API介紹

由于View Animation 系統(tǒng)已在android.view.animation中定義了很多的插值器,你可以直接利用到你的屬性動畫中。 Animator雖然提供了創(chuàng)建動畫的基本框架,但你不應(yīng)當(dāng)直接使用這個類,由于它只提供了很少的功能,需要去擴大才能完全支持動畫。下面介紹的是1些屬性動畫系統(tǒng)中的主要類。



2.1 Animators

 1.ValueAnimator

屬性動畫中的主要的時序引擎,如動畫時間,開始、結(jié)束屬性值,相應(yīng)時間屬性值計算方法等。包括了所有計算動畫值的核心函數(shù)。也包括了每個動畫時間上的細(xì)節(jié),信息,1個動畫是不是重復(fù),是不是監(jiān)聽更新事件等,并且還可以設(shè)置自定義的計算類型。


全部Property Animation動畫有兩個步聚:

1.計算屬性值
2.為目標(biāo)對象的屬性設(shè)置屬性值,即利用和刷新動畫。

ValueAnimiator只完成了第1步工作,如果要完成第2步,你必須監(jiān)聽由ValueAnimator計算得到的屬性值,并修改目標(biāo)對象。需要實現(xiàn)ValueAnimator .onUpdateListener 接口,自己去處理對象的動畫邏輯,比如:

ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f); animation.setDuration(1000); animation.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Log.i("update", ((Float) animation.getAnimatedValue()).toString()); } }); animation.setInterpolator(new CycleInterpolator(3)); animation.start();

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


2.3 Interpolators

插值器:時間的函數(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的源碼為:

AccelerateDecelerateInterpolator public float getInterpolation(float input) { return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; }
在下面的圖中,也能夠看到AccelerateDecelerate的Formula(公式)和其getInterpolation(input)方法相對應(yīng)的函數(shù)值。

截圖來自: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
public float getInterpolation(float input) { return input; }


3、利用動畫


3.1、使用ValueAnimator添加動畫

ValueAnimator類可以為1些動畫指定1系列的int,float,color值。通過調(diào)用工廠方法ofInt(),ofFloat().ofObject()來獲得1個ValueAnimator.
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f); animation.setDuration(1000); animation.start();

上面這段是無效的代碼,由于這里根本就沒有動畫目標(biāo)的影子,也沒有在ValueAnimator的監(jiān)聽中獲得計算得到的屬性值去更新目標(biāo)對象,所以不會有動畫效果。


你需要為動畫指定1個自定義的類型:

ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue); animation.setDuration(1000); animation.start();


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


3.2、使用ObjectAnimator添加動畫


更加簡便,動畫屬性會自動更新,不用再像ValueAnimator那樣自己去實現(xiàn)更新的動畫邏輯,但需要遵守1定的規(guī)則。


ObjectAnimator是ValueAnimator的子類,并且同時具有時序引擎和屬性值計算和自動更新屬性值的功能,使得為對象添加動畫變得更加簡單。因此你不再需要去實現(xiàn)ValueAnimator.AnimatorUpdateListener去更新動畫的屬性了。
實例化1個ObjectAnimator與實例化1個ValueAnimator是類似的,但是你應(yīng)當(dāng)指定對象和對象的某1屬性的名字(String 類型),和動畫的起始和結(jié)束值。
ObjectAnimator anim = ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f); anim.setDuration(1000); anim.start();


ObjectAnimator的自動更新功能,依賴于屬性身上的setter和getter方法,所以為了讓ObjectAnimator能夠正確的更新屬性值,你必須遵從以下規(guī)范:


1.  該對象的屬性必須有g(shù)et和set方法(方法的格式必須是駝峰式),方法格式為set(),由于ObjectAnimator會自動更新屬性,它必須能夠訪問到屬性的setter方法,比如屬性名為foo,你就需要1個setFoo()方法,如果setter方法不存在,你有3種選擇:
a.添加setter方法
b.使用包裝類。通過該包裝類通過1個有效的setter方法獲得或改變屬性值的方法,然后利用于原始對象。

c.使用ValueAnimator代替。


(這3點的意思總結(jié)起來就是1定要有1個setter方法,讓ObjectAnimator能夠訪問到)

2.  如果你為ObjectAnimator的工廠方法的可變參數(shù)只傳遞了1個值,那末會被作為動畫的結(jié)束值。因此,你的目標(biāo)對象屬性上必須要有1個getter方法,用于獲得動畫的起始值。這個獲得方法必須使用get()的格式。例如,屬性是foo,就必須有1個getFoo方法。


3.  注意,屬性的getter方法和setter方法必須必須是相對應(yīng)的,比如你構(gòu)造了1個以下的ObjectAnimator,那末getter和setter方法就應(yīng)當(dāng)為:

targetObject.setPropName(float) 和targetObject.getPropName(float) :

ObjectAnimator.ofFloat(targetObject, "propName", 1f)


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ù)需要,不需實時更新的動畫,需要你自己去強迫更新。


3.3、AnimatorSet編排多個動畫

很多時候,你需要在1個動畫的開始或結(jié)束點去播放另外一個動畫,Android系統(tǒng)允許你綁定多個動畫到1個AnimatorSet中,因此你可以指定這些動畫是不是同時啟動或有序或延遲進行。你也能夠相互內(nèi)嵌AnimatorSet。下面的代碼來自Google Sample彈力球Sample,按順序播放了以下動畫:


1、播放 bounceAnim.
2、同時播放 squashAnim1, squashAnim2, stretchAnim1, and stretchAnim2 
3、播放  bounceBackAnim.
4、播放 fadeAnim.
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();

更多細(xì)節(jié),你可以參考APIDemo,APIDemo在大家的SDK中都有,直接導(dǎo)入便可。

4、Animation Listeners

你可以通過以下監(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é)束的。


ValueAnimator.AnimatorUpdateListener

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方法。
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f); fadeAnim.setDuration(250); fadeAnim.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animation) { balls.remove(((ObjectAnimator)animation).getTarget()); }


5、使用TypeEvaluator

如果你想添加1種動畫系統(tǒng)中沒有的計算類型,就需要自己通過實現(xiàn)TypeEvaluator接口去創(chuàng)建自己的evaluator。Android系統(tǒng)可以辨認(rèn)的類型是:int,float或color。對應(yīng)的java類分別為 IntEvaluator、 FloatEvaluator、 ArgbEvaluator 。


TypeEvaluator接口只有1個方法,就是evaluate()方法,它允許你使用的animator返回1個當(dāng)前動畫點的屬性值,F(xiàn)loatEvaluator示例:
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); } }

我們再來看1下IntEvaluators的源碼:

/** * This evaluator can be used to perform type interpolation betweenintvalues. */ public class IntEvaluator implements TypeEvaluator{ public Integer evaluate(float fraction, Integer startValue, Integer endValue) { int startInt = startValue; return (int)(startInt + fraction * (endValue - startInt)); } }
ArgbEvaluator的部份源碼,由于是106進制色彩值,前部份做了1些位運算的操作,這里貼出的是最后返回值的代碼:
return (int)((startA + (int)(fraction * (endA - startA))) << 24) | (int)((startR + (int)(fraction * (endR - startR))) << 16) | (int)((startG + (int)(fraction * (endG - startG))) << 8) | (int)((startB + (int)(fraction * (endB - startB))));


大家可以看到,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ù)做了處理。


TimeInterpolatorTypeEvaluator的區(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ù)

Interpolator 和 evaluator 都是可以自定義函數(shù)的。 前者:只能修改fraction (多數(shù)場景可以滿足,將本來線性的運動修改成非線性的) 后者:能拿到所有數(shù)據(jù),然后去返回終究的值(終極利器,傳入他的有3個參數(shù) (float fraction, T startValue, T endValue)) getInterpolation(float input) evaluate(float fraction, Number startValue, Number endValue)

從上述回復(fù)我們可以看到,evaluate方法接收3個參數(shù),第1個參數(shù)fraction我們可以實現(xiàn)TimeInterpolator接口復(fù)寫 getInterpolation(float input)來控制,但是startValue和endValue我們是拿不到的,這才是關(guān)鍵。如果有些動畫值的計算需要startValue和endValue,那末你就只能在evaluate中去定義你的計算函數(shù)了。在代碼家AnimationEasingFunctions 動畫庫有些屬性值計算就是用到了這兩個值,所以他統(tǒng)1在evaluate中定義函數(shù)。(這應(yīng)當(dāng)就是缺少實踐吧,只有自己用的時候,才會發(fā)現(xiàn)問題。不能不佩服代碼家的經(jīng)驗,開源了好幾個很棒的庫,要是還不了解的朋友,請立刻關(guān)注吧,對你的學(xué)習(xí)1定會有幫助:https://github.com/daimajia

以上的分析是基于系統(tǒng)支持的float類型值來分析的,在該條件下,由于我們的計算函數(shù)需要startValue或endValue來計算屬性值,所以只能將函數(shù)定義在evaluate方法中。我的分析實際上是從數(shù)據(jù)類型的角度斟酌的,另外我們知道Property Anim系統(tǒng)的1大擴大就是可以對任何對象進行添加動畫,那末如果你的數(shù)據(jù)類型不是float、int、color類型,那末你肯定是在TypeEvaluator中定義了,在Interpolator中定義明顯不適合。

所以綜上所述,TypeEvaluator所做的是根據(jù)數(shù)據(jù)結(jié)構(gòu)計算終究的屬性值,允許你定義自己的數(shù)據(jù)結(jié)構(gòu),這才是官方對它的真正定義,如果你的計算函數(shù)需要startValue和endValue的時候,你也只能在evaluate中定義計算函數(shù),而Interpolator更偏向于你定義1種運動的變化率,比如勻速、加速、減速等,官方對Interpolator的定義也確切是這樣的:
A time interpolator defines the rate of change of an animation. This allows animations to have non-linear motion, such as acceleration and deceleration.

弄清TimeInterpolator和TypeEvaluator非常重要,如果你希望要自定義自己的動畫,那末這兩個函數(shù)肯定是關(guān)鍵部份,1個是定義動畫變化率,1個是定義數(shù)據(jù)結(jié)構(gòu)和屬性值計算方式,二者共同決定了1個動畫的運動。


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

/* * 獲得動畫值,通過給定的elapsed fraction 和evaluators去計算中間值。該函數(shù)將傳遞的fraction映照到恰當(dāng)?shù)膋eyframe和fraction * 終究計算返回interpolated value. * 注意:傳入的fraction可能落在[0⑴]范圍以外,這樣的情況,我們只使用2個KeyFrameSet。只有2幀的時候,做了特別優(yōu)化。 * 每幀還可以具有自己的Interpolator */ public float getFloatValue(float fraction) { if (mNumKeyframes == 2) {//對只有兩幀的情況,單獨處理,做了優(yōu)化 if (firstTime) { firstTime = false; firstValue = ((FloatKeyframe) mKeyframes.get(0)).getFloatValue(); lastValue = ((FloatKeyframe) mKeyframes.get(1)).getFloatValue(); deltaValue = lastValue - firstValue; } if (mInterpolator != null) { fraction = mInterpolator.getInterpolation(fraction); } if (mEvaluator == null) { return firstValue + fraction * deltaValue; } else { return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).floatValue(); } } if (fraction <= 0f) {//fraction<=0,為了更接近獲得第1幀和第2幀做處理 final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);//這里的fraction就是0 final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(1); float prevValue = prevKeyframe.getFloatValue(); float nextValue = nextKeyframe.getFloatValue(); float prevFraction = prevKeyframe.getFraction(); float nextFraction = nextKeyframe.getFraction(); final TimeInterpolator interpolator = nextKeyframe.getInterpolator(); if (interpolator != null) { fraction = interpolator.getInterpolation(fraction); } float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction); return mEvaluator == null ? prevValue + intervalFraction * (nextValue - prevValue) : ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)). floatValue(); } else if (fraction >= 1f) {//由于fraction>=1,為了更接近fraction,獲得最后的兩幀做處理 final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 2); final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 1); float prevValue = prevKeyframe.getFloatValue(); float nextValue = nextKeyframe.getFloatValue(); float prevFraction = prevKeyframe.getFraction(); float nextFraction = nextKeyframe.getFraction(); final TimeInterpolator interpolator = nextKeyframe.getInterpolator(); if (interpolator != null) { fraction = interpolator.getInterpolation(fraction); } float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction); return mEvaluator == null ? prevValue + intervalFraction * (nextValue - prevValue) : ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)). floatValue(); } FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);// for (int i = 1; i < mNumKeyframes; ++i) {//循環(huán)遍歷, FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(i); if (fraction < nextKeyframe.getFraction()) {//如果后1幀elapsed fraction 大于 前1個 elapsed fraction,才有效 final TimeInterpolator interpolator = nextKeyframe.getInterpolator();//獲得當(dāng)前幀的Interpolator if (interpolator != null) {//當(dāng)前幀有自己的Interpolator,則重新計算fraction fraction = interpolator.getInterpolation(fraction); } float intervalFraction = (fraction - prevKeyframe.getFraction()) //prevKeyframe.getFraction() = 0 (nextKeyframe.getFraction() - prevKeyframe.getFraction()); float prevValue = prevKeyframe.getFloatValue();//計算前1幀的值 float nextValue = nextKeyframe.getFloatValue();//計算后1幀的值 return mEvaluator == null ? prevValue + intervalFraction * (nextValue - prevValue) ://未定義Evaluator,則簡單的返回,屬性值計算結(jié)束 ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).//依照自定義的Evaluator來計算屬性值 floatValue(); } prevKeyframe = nextKeyframe; } // shouldn't get here return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).floatValue(); }


可以看到這里1共處理了4種情況:

mKeyframeNums == 2 

fraction <= 0

fraction >= 1

fraction在(0,1)之間且mKeyframeNums != 2 


我們先看看keyframe.getFraction()獲得到的是甚么值:


PropertyViewHolder

public void setFloatValues(float... values) { mValueType = float.class; mKeyframeSet = KeyframeSet.ofFloat(values); }

KeyframeSet.ofFloat(values)

public static KeyframeSet ofFloat(float... values) { int numKeyframes = values.length; FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)]; if (numKeyframes == 1) { keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f); keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]); } else { keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]); for (int i = 1; i < numKeyframes; ++i) { keyframes[i] = (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);//這里是關(guān)鍵 } } return new FloatKeyframeSet(keyframes); }

這里有個從角標(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。

@return The interpolation value. This value can be more than 1.0 for * interpolators which overshoot their targets, or less than 0 for * interpolators that undershoot their targets. */ float getInterpolation(float input);
在mKeyframeNums  = 2 的時候,getInterpolation(input)的值會直接傳入到evaluate中,而getInterpolation(input)的值可以是[0,1]以外的值。因此evaluate接收到的fraction便可能大于1,或小于0,。大于1,說明波動比較大,獲得到的屬性值將大于目標(biāo)值。


其實當(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種情況的處理:

float intervalFraction = (fraction - prevKeyframe.getFraction()) / (nextKeyframe.getFraction() - prevKeyframe.getFraction()); return mEvaluator == null ? prevValue + intervalFraction * (nextValue - prevValue) ://未定義Evaluators,則簡單的返回,屬性值計算結(jié)束 ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).//依照自定義的Evaluators來處理屬性值 floatValue();

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

final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0); final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(1);

選擇的是第1幀(從上面的賦值來知道,第1幀的fraction為固定值0)和第2幀

prevkeyframeFraction = 0,nextKeyframeFraction  = 1 / 2:

 


  fraction >= 1

final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 2); final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 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的那1幀。

兜了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系列工作

/* * 返回1個ObjectAnimator對象, * 如果可變參數(shù)values: * 只傳遞1個值:那末該值作為屬性結(jié)束值, * 傳2個值,則為起始和結(jié)束值。 * 2個以上,則起始值,過渡值,結(jié)束值 */ public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) { ObjectAnimator anim = new ObjectAnimator(target, propertyName); anim.setFloatValues(values); return anim; }
ValueAnimator.java /** * 主要是設(shè)置values值 * 如果不是通過工廠方法獲得ObjectAnimator對象,而是通過構(gòu)造
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 免费日本视频 | 伊人国产精品 | 成人黄色电影在线观看 | 国产亚洲二区 | 国产成人精品久久二区二区91 | 国产一区二区三区高清 | 在线观看日韩视频 | 亚洲精品电影在线 | 综合久久国产九一剧情麻豆 | 黄色片视频在线观看 | www.日韩大片| 亚洲久久久久 | 国产在线不卡视频 | 操女人在线 | 久久精品无码一区二区三区 | 一区在线观看视频 | 免费国产一区二区 | 91精品网站 | 成人精品一区二区三区电影黑人 | 91久久国产综合久久蜜月精品 | 久久99久久99| 国产免费看片 | 久久综合九色综合久久久精品综合 | 国产精品成人一区二区三区 | 亚洲国产成人精品久久久国产成人一区 | 中文字幕在线视频免费观看 | 日韩精品一区二区三区免费观看 | 中文精品视频 | 午夜高清 | 成人不卡 | 欧美日韩精品 | 天天干夜夜拍 | 久久久精品免费 | 欧美亚洲一区二区三区 | 九九九精品视频 | 99国产精品久久久久久久 | 亚洲国产日韩精品 | 日韩一区二区三区在线播放 | 国产伦精品一区 | 综合久久一区 | 成人91|