Property Animation中最重要,最基礎的一個類就是ValueAnimator了。Property Animation利用ValueAnimator來追蹤記錄對象屬性已經變化了多長時間及當前這個時間點的值。
而在ValueAnimator中,又封裝了兩個類:
1)TimeInterpolator,也稱插值器,是來計算當前動畫運動的一個跟時間有關係的比例因素。
2)TypeEvaluator,這個就是利用TimeInterpolator計算出來的因子來算出當前動畫運行到的位置。
這樣講太抽象了,我們還是先用自然語言來描述一下整個動畫的過程吧。
動畫的原理,其實就是一幀幀的畫面順著時間順序,在我們眼中形成視覺殘留的效果。所以在動畫中,時間的概念是很重要的,只有時間的變化,才能形成動畫效果。
0)動畫準備開始,我們在這裡設定了一個動畫的時間長度(duration),如果不設定的話,動畫的時間長度就是300毫秒,每個畫面顯示的時間是10ms。同時也設定了某個屬性值在這個時間段中變化的起始值start和結束值end,意思就是說,在duration時間中,屬性值要從start 變化到 end。
1)動畫開始了,過了 t 時間,ValueAnimator會根據 t / duration 算出一個時間消逝的比例因素(elapsed fraction),意思就是說,現在時間到 t了,我們假設總的時間的duration就是3t吧,那就是現在已經過了1/3時間了,那這個屬性值也應該要變化到1/3了。
2)動畫繼續,現在到了2t了,那麼現在動畫時間已經過了2/3了,那麼這個屬性值是不是已經變化到2/3了呢。
3)現在到了3t了,動畫結束了,屬性值就已經從start變成end值了。
那麼現在問題來了,如果都是這樣算的話,那動畫不就一直是很勻速的了嗎?是的,如果用的是LinearInterpolator的話。
TimeInterpolatorTimeInterpolator就是用來改變我們這個動畫速度的這樣一個類了。為什麼叫插值器呢?我理解就是,本來動畫踩著時間點,一步一步走的挺好的,它硬生生在中間的插了些值進去,或者抽了一些值出去,讓整條路變得不好走了,前面變然變上坡了,走起來就慢了,本來過去 t 時間之後,動畫的畫面也應該在1/3的位置了,但是路不好走,它就走不到1/3,而可能只走了1/4了,而後面是下坡,一激動,步伐就快了許多,又趕上去了,但是不管中間的路怎麼變化,時間點一到,一定是剛剛好落在最終的位置上的。Android中提供的Interpolator主要有九個:1)AccelerateDecelerateInterpolator:先加速再減速。
2)AccelerateInterpolator:一直加速。
3)AnticipateInterpolator:先往後一下,再嗖的一聲一往無前。
4)AnticipateOvershootInterpolator:先往後一下,再一直往前超過終點,再往回收一下。
5)BounceInterpolator:最後像個小球彈幾下。
6)CycleInterpolator:重複幾次,感覺就是環形進度條那種,具體我還沒試過。
7)DecelerateInterpolator:一直減速。
8)LinearInterpolator:線性,這個就是我們上面講到的很均勻的了。
9)OvershootInterpolator:到了終點之後,超過一點,再往回走。有個參數可以定義,超過的力度。
這些Interpolator都是實現了TimeInterpolator介面的類,它們只需要實現一個方法:getInterpolation (float input),將這個input根據自己的需求重新計算這個比例
第一步:當到了某時間t之後,ValueAnimator會算出某個比例 fraction = t / duration,而Interpolator會接收這個比例fraction,再調用其getInterpolation方法將這個比例因素重新計算一下,返回一個新的比例因素,比如LinearInterpolator實現的方法就是什麼都不變,如下:
public float getInterpolation(float input) { return input;}而 AccelerateDecelerateInterpolator 則會利用餘弦函數的對稱性變化計算這個比例因素,如下:
public float getInterpolation(float input) { return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;}
如上所述,通過第一步 Interpolator 的插值,我們會得到一個比例因素,接下來就是要用到我們的TypeEvaluator了。
TypeEvaluator
第二步:TypeEvaluator會接受第一步中算出來的比例因素,然後算出當前的屬性的值,將其返回給ValuaAnimator,由ValueAnimator去設定對應屬性的值。比如,我自己寫了一個BezierTypeEvaluator,根據時間的變化來讓一個按鈕沿著貝茲路徑移動,如下:
class BezierEvaluator implements TypeEvaluator{@Overridepublic PointF evaluate(float fraction, PointF startValue,PointF endValue) {final float t = fraction;float oneMinusT = 1.0f - t;PointF point = new PointF();PointF point0 = (PointF)startValue;PointF point1 = new PointF();point1.set(width, 0);PointF point2 = new PointF();point2.set(0, height);PointF point3 = (PointF)endValue;point.x = oneMinusT * oneMinusT * oneMinusT * (point0.x) + 3 * oneMinusT * oneMinusT * t * (point1.x)+ 3 * oneMinusT * t * t * (point2.x)+ t * t * t * (point3.x);point.y = oneMinusT * oneMinusT * oneMinusT * (point0.y) + 3 * oneMinusT * oneMinusT * t * (point1.y)+ 3 * oneMinusT * t * t * (point2.y)+ t * t * t * (point3.y);return point;}}
自訂TypeEvaluator,我們必須實現其evaluate方法,目的就是計算出目前的對象對應屬性的值,而它會接收三個參數,一個是上文中通過interpolator算出的比例,還有我們在建立動畫時設定的起始值和結束值。
ValueAnimator.AnimatorUpdateListener既然我們已經算出了在 t 時刻,對象的某個屬性的值,那麼我們要把這個值重新設定到對象中,才能夠起作用啊。所以ValueAnimator也提供了一個內部的Listener介面,其只有一個方法,就是擷取TypeEvaluator計算出來的值,並設定給對應的屬性,比如我們Demo中的代碼:
valueAnimator.addUpdateListener(new AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {PointF pointF = (PointF)animation.getAnimatedValue();button.setX(pointF.x);button.setY(pointF.y);}});
我們在這裡改變Button的X座標和Y座標,從而改變其具體的位置。至於validate,然後引起重新繪製的過程,對於這些基本的屬性,ValueAnimator已經幫我們實現了。下面,我們看看,然後再總結一下ValueAnimator的實現機制。下載
嗯,這一篇文章大概就是這樣了,大家如果有興趣瞭解Property Animation的應用的話,可以看一下Android動畫學習Demo(2) 關於Property Animation的用法及總結
最後還是要提醒一下,Property Animation是3.0以後才支援的,如果大家想在3.0之前去應用這些屬性的話,可以去下載jake wharton的nineoldandroids包,基本上都可以直接將方法套上,不過據我實驗,還是有某些方法,比如 PropertyValuesHolder就會有些bug出現的。我把這個包也放在這裡吧,
點擊NineoldAndroids下載