鍍金池/ 教程/ Android/ 高級進階(一)
聯(lián)合動畫的 XML 實現(xiàn)與使用示例
Interpolator 插值器
高級進階(二)
ObjectAnimator 基本使用
ValueAnimator 基本使用
alpha、scale、translate、rotate、set 的 xml 屬性及用法
PropertyValuesHolder 與 Keyframe
layoutAnimation 與 gridLayoutAnimation
自定義控件三部曲之動畫篇(十三)——實現(xiàn)ListView Item進入動畫
自定義控件三部曲之動畫篇(十二)——animateLayoutChanges與LayoutTransition
高級進階(一)
代碼生成 alpha、scale、translate、rotate、set 及插值器動畫
聯(lián)合動畫的代碼實現(xiàn)

高級進階(一)

上一篇給大家介紹了 ValueAnimator 的大部分函數(shù)的用法,不過還都是些簡單的用法,這篇我們帶大家來看看有關(guān)加速器、animator 和 keyFrame 的知識。

一、插值器

插值器,也叫加速器;有關(guān)插值器的知識,我在《Animation 動畫詳解(二)——Interpolator 插值器》中專門講過,大家可以先看看這篇文章中各個加速器的效果。 這里再講一下什么是插值器。我們知道,我們通過 ofInt(0,400)定義了動畫的區(qū)間值是 0 到 400;然后通過添加 AnimatorUpdateListener 來監(jiān)聽動畫的實時變化。那么問題來了,0-400 的值是怎么變化的呢?像我們騎自行車,還有的快有的慢呢;這個值是勻速變化的嗎?如果是,那我如果想讓它先加速再減速的變化該怎么辦? 這就是插值器的作用!插值器就是用來控制動畫區(qū)間的值被如何計算出來的。比如 LinearInterpolator 插值器就是勻速返回區(qū)間點的值;而 DecelerateInterpolator 則表示開始變化快,后期變化慢;其它都類似,下面我們就看看 ValueAnimator 中插值器的應(yīng)用方法,然后通過自定義一個插值器來看看插值器到底是什么。

1、使用插值器

我們就以 BounceInterpolator(彈跳插值器)為例做一個實驗,BounceInterpolator 的解釋是動畫結(jié)束的時候彈起;我們來看一下效果:

http://wiki.jikexueyuan.com/project/android-animation/images/60.gif" alt="" />

下面我們就來看一下利用 ValueAnimator 是如何實現(xiàn)的。布局和上一篇的都一樣,這里就不再細講了,我們著重來看一下,當點擊 start anim 按鈕以后是怎么做的,代碼如下:

ValueAnimator animator = ValueAnimator.ofInt(0,600);  

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
    @Override  
    public void onAnimationUpdate(ValueAnimator animation) {  
        int curValue = (int)animation.getAnimatedValue();  
        tv.layout(tv.getLeft(),curValue,tv.getRight(),curValue+tv.getHeight());  
    }  
});  
animator.setDuration(1000);  
animator.setInterpolator(new BounceInterpolator());  
animator.start(); 

如果大家已經(jīng)看懂了上篇,這段代碼就非常容易理解了,在監(jiān)聽中,我們只改變 textview 的 top 和 bottom 的位置,讓它跟著當前動畫的值來改變它當前的 top 和 bottom 的位置。然后我們利用 setDuration(1000)給它設(shè)置上做一次動畫所需要的時長,然后通過 setInterpolator()給它設(shè)置插值器,也就是過渡值變化的規(guī)則; 從效果圖中也可以看出,插值器的意義其實就相當于物理公式中的加速度參數(shù),所以這也就是它也叫加速器的原因。 源碼在文章底部給出 在學會了怎么使用加速器以后,我們來看看如何自定義一個加速器吧

2、自定義加速器

1、概述 在這段,我們就開始著手自己寫一個加速器了,在寫加速器之前,先看看人家的加速器是怎么寫的吧。 先看看 LinearInterpolator:

public class LinearInterpolator implements Interpolator {  

    public LinearInterpolator() {  
    }  

    public LinearInterpolator(Context context, AttributeSet attrs) {  
    }  

    public float getInterpolation(float input) {  
        return input;  
    }  
}  
public interface Interpolator extends TimeInterpolator {  
}

LinearInterpolator 實現(xiàn)了 Interpolator 接口;而 Interpolator 接口則直接繼承自 TimeInterpolator,而且并沒有添加任何其它的方法。 那我們來看看 TimeInterpolator 接口都有哪些函數(shù)吧:

/** 
 * A time interpolator defines the rate of change of an animation. This allows animations 
 * to have non-linear motion, such as acceleration and deceleration. 
 */  
public interface TimeInterpolator {  

    /** 
     * Maps a value representing the elapsed fraction of an animation to a value that represents 
     * the interpolated fraction. This interpolated value is then multiplied by the change in 
     * value of an animation to derive the animated value at the current elapsed animation time. 
     * 
     * @param input A value between 0 and 1.0 indicating our current point 
     *        in the animation where 0 represents the start and 1.0 represents 
     *        the end 
     * @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);  
}  

這里是 TimeInterpolator 的代碼,它里面只有一個函數(shù) float getInterpolation(float input);我們來講講這個函數(shù)是干什么的。 參數(shù) input:input 參數(shù)是一個 float 類型,它取值范圍是 0 到 1,表示當前動畫的進度,取 0 時表示動畫剛開始,取 1 時表示動畫結(jié)束,取 0.5 時表示動畫中間的位置,其它類推。 返回值:表示當前實際想要顯示的進度。取值可以超過 1 也可以小于 0,超過 1 表示已經(jīng)超過目標值,小于 0 表示小于開始位置。 對于 input 參數(shù),它表示的是當前動畫的進度,勻速增加的。什么叫動畫的進度,動畫的進度就是動畫在時間上的進度,與我們的任何設(shè)置無關(guān),隨著時間的增長,動畫的進度自然的增加,從 0 到 1;input 參數(shù)相當于時間的概念,我們通過 setDuration()指定了動畫的時長,在這個時間范圍內(nèi),動畫進度肯定是一點點增加的;就相當于我們播放一首歌,這首歌的進度是從 0 到 1 是一樣的。 而返回值則表示動畫的數(shù)值進度,它的對應(yīng)的數(shù)值范圍是我們通過 ofInt(),ofFloat()來指定的,這個返回值就表示當前時間所對應(yīng)的數(shù)值的進度。 我們先看看下面這段代碼:

ValueAnimator anim = ValueAnimator.ofInt(100, 400);    
anim.setDuration(1000);    
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {    
    @Override    
    public void onAnimationUpdate(ValueAnimator animation) {    
        float currentValue = (float) animation.getAnimatedValue();    
        Log.d("TAG", "cuurent value is " + currentValue);    
    }    
});    
anim.start();  

我們知道,在我們添加了 AnimatorUpdateListener 的監(jiān)聽以后,通過在監(jiān)聽函數(shù)中調(diào)用 animation.getAnimatedValue()就可以得到當前的值; 那當前的值是怎么來的呢?見下面的計算公式:(目前這么理解,后面會細講真實情況) 當前的值 = 100 + (400 - 100) 顯示進度 其中 100 和 400 就是我們設(shè)置的 ofInt(100,400)中的值,這個公式應(yīng)該是比較容易理解的,就相當于我們做一個應(yīng)用題: 小明從 100 的位置開始出發(fā)向 400 的位置開始跑去,在走到全程距離 20%位置時,請問小明在哪個數(shù)字點上? 當前的值 = 100 + (400 -100) 0.2; 很簡單的應(yīng)用題,ofInt()中 AnimatorUpdateListener 中的當前值就是這么來的。從這里大家可以看到,顯示進度就表示的是當前的值的位置。但由于我們可以通過指定 getInterpolation()的返回值來指定當前的顯示值的進度,所以隨著時間的增加,我們可以讓值隨意在我們想讓它在的位置。 再重復一遍,input 參數(shù)與任何我們設(shè)定的值沒關(guān)系,只與時間有關(guān),隨著時間的增長,動畫的進度也自然的增加,input 參數(shù)就代表了當前動畫的進度。而返回值則表示動畫的當前數(shù)值進度 通過上面我們應(yīng)該知道了 input 參數(shù) getInterpolation()返回值的關(guān)系了,下面我們來看看 LinearInterpolator 是如何重寫 TimeInterpolator 的:

public class LinearInterpolator implements Interpolator {  

    …………  

    public float getInterpolation(float input) {  
        return input;  
    }  
}  

從上面可以看到,LinearInterpolator 在 getInterpolation 函數(shù)中,直接把 input 值返回,即以當前動畫的進度做為動畫的數(shù)值進度,這也就表示當前動畫的數(shù)值進度與動畫的時間進度一致,比如,如果當前動畫進度為 0,那動畫的數(shù)值進度也是 0,那如果動畫進度為 0.5,那動畫的數(shù)值進度也是在 0.5,當動畫結(jié)束,動畫的進度就變成 1 了,而動畫的數(shù)值進度也是 1 了。 下面我們就用一個例子來講一下如何自定義插值器。 2、示例 從上面的講解中也可以看到,我們自定義插值器,只需要實現(xiàn) TimeInterpolator 接口就可以了:

public class MyInterploator implements TimeInterpolator {  
    @Override  
    public float getInterpolation(float input) {  
        return 1-input;  
    }  
} 

在 getInterpolation 函數(shù)中,我們將進度反轉(zhuǎn)過來,當傳 0 的時候,我們讓它數(shù)值進度在完成的位置,當完成的時候,我們讓它在開始的位置 然后使用我們的插值器:

ValueAnimator animator = ValueAnimator.ofInt(0,600);  

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
    @Override  
    public void onAnimationUpdate(ValueAnimator animation) {  
        int curValue = (int)animation.getAnimatedValue();  
        tv.layout(tv.getLeft(),curValue,tv.getRight(),curValue+tv.getHeight());  
    }  
});  
animator.setDuration(1000);  
animator.setInterpolator(new MyInterploator());  
animator.start(); 

這里使用自定義插值器的方法與使用普通插值器的方法是完全一樣的,下面來看看效果:

http://wiki.jikexueyuan.com/project/android-animation/images/61.gif" alt="" />

從效果圖中可見,我們將數(shù)值進度倒序返回——即隨著動畫進度的推進,動畫的數(shù)值進度從結(jié)束位置進行到起始位置; 到這里,想必大家應(yīng)該已經(jīng)理解了 getInterpolation(float input)函數(shù)中 input 參數(shù)與返回值的關(guān)系,在重寫插值器時,需要強有力的數(shù)學知識做基礎(chǔ),一般而言,都是通過數(shù)學公式來計算插值器的變化趨勢的,大家可以再分析分析其它幾個插值器的寫法;可以把它他們總結(jié)成公式,放到公式畫圖軟件里,看看對應(yīng)的數(shù)學圖在(0,1)之間的走向,這個走向就是插值器在數(shù)值變化時的樣子。

源碼在文章底部給出

二、Evaluator

1、概述

我們先不講什么是 Evaluator,我們先來看一張圖:

http://wiki.jikexueyuan.com/project/android-animation/images/10.png" alt="" />

這幅圖講述了從定義動畫的數(shù)字區(qū)間到通過 AnimatorUpdateListener 中得到當前動畫所對應(yīng)數(shù)值的整個過程。下面我們對這四個步驟具體講解一下: (1)、ofInt(0,400)表示指定動畫的數(shù)字區(qū)間,是從 0 運動到 400; (2)、加速器:上面我們講了,在動畫開始后,通過加速器會返回當前動畫進度所對應(yīng)的數(shù)字進度,但這個數(shù)字進度是百分制的,以小數(shù)表示,如 0.2 (3)、Evaluator:我們知道我們通過監(jiān)聽器拿到的是當前動畫所對應(yīng)的具體數(shù)值,而不是百分制的進度。那么就必須有一個地方會根據(jù)當前的數(shù)字進度,將其轉(zhuǎn)化為對應(yīng)的數(shù)值,這個地方就是 Evaluator;Evaluator 就是將從加速器返回的數(shù)字進度轉(zhuǎn)成對應(yīng)的數(shù)字值。所以上部分中,我們講到的公式:

[java] view plain 當前的值 = 100 + (400 - 100)* 顯示進度
這個公式就是在 Evaluator 計算的;在拿到當前數(shù)字進度所對應(yīng)的值以后,將其返回 (4)、監(jiān)聽器:我們通過在 AnimatorUpdateListener 監(jiān)聽器使用 animation.getAnimatedValue()函數(shù)拿到 Evaluator 中返回的數(shù)字值。 講了這么多,Evaluator 其實就是一個轉(zhuǎn)換器,他能把小數(shù)進度轉(zhuǎn)換成對應(yīng)的數(shù)值位置

2、各種 Evaluator

首先,加速器返回的小數(shù)值,表示的是當前動畫的數(shù)值進度。無論是利用 ofFloat()還是利用 ofInt()定義的動畫都是適用的。因為無論是什么動畫,它的進度必然都是在 0 到 1 之間的。0 表示沒開始,1 表示數(shù)值運動的結(jié)束,對于任何動畫都是適用的。 但 Evaluator 則不一樣,我們知道 Evaluator 是根據(jù)加速器返回的小數(shù)進度轉(zhuǎn)換成當前數(shù)值進度所對應(yīng)的值。這問題就來了,如果我們使用 ofInt()來定義動畫,動畫中的值應(yīng)該都是 Int 類型,如果我用 ofFloat()來定義動畫,那么動畫中的值也都是 Float 類型。所以如果我用 ofInt()來定義動畫,所對應(yīng)的 Evaluator 在返回值時,必然要返回 Int 類型的值。同樣,我們?nèi)绻?ofFloat 來定義動畫,那么 Evaluator 在返回值時也必然返回的是 Float 類型的值。 所以每種定義方式所對應(yīng)的 Evaluator 必然是它專用的;Evaluator 專用的原因在于動畫數(shù)值類型不一樣,在通過 Evaluator 返回時會報強轉(zhuǎn)錯誤;所以只有在動畫數(shù)值類型一樣時,所對應(yīng)的 Evaluator 才能通用。所以 ofInt()對應(yīng)的 Evaluator 類名叫 IntEvaluator,而 ofFloat()對應(yīng)的 Evaluator 類名叫 FloatEvaluator; 在設(shè)置 Evaluator 時,是通過 animator.setEvaluator()來設(shè)置的,比如:

ValueAnimator animator = ValueAnimator.ofInt(0,600);  

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
    @Override  
    public void onAnimationUpdate(ValueAnimator animation) {  
        int curValue = (int)animation.getAnimatedValue();  
        tv.layout(tv.getLeft(),curValue,tv.getRight(),curValue+tv.getHeight());  
    }  
});  
animator.setDuration(1000);  
animator.setEvaluator(new IntEvaluator());  
animator.setInterpolator(new BounceInterpolator());  
animator.start(); 

但大家會說了,在此之前,我們在使用 ofInt()時,從來沒有給它定義過使用 IntEvaluator 來轉(zhuǎn)換值啊,那怎么也能正常運行呢?因為 ofInt 和 ofFloat 都是系統(tǒng)直接提供的函數(shù),所以在使用時都會有默認的加速器和 Evaluator 來使用的,不指定則使用默認的;對于 Evaluator 而言,ofInt()的默認 Evaluator 當然是 IntEvaluator;而 FloatEvalutar 默認的則是 FloatEvalutor; 上面,我們已經(jīng)弄清楚 Evaluator 定義和使用方法,下面我們就來看看 IntEvaluator 內(nèi)部是怎么實現(xiàn)的吧:

/** 
 * This evaluator can be used to perform type interpolation between <code>int</code> values. 
 */  
public class IntEvaluator implements TypeEvaluator<Integer> {  

    /** 
     * This function returns the result of linearly interpolating the start and end values, with 
     * <code>fraction</code> representing the proportion between the start and end values. The 
     * calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>, 
     * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>, 
     * and <code>t</code> is <code>fraction</code>. 
     * 
     * @param fraction   The fraction from the starting to the ending values 
     * @param startValue The start value; should be of type <code>int</code> or 
     *                   <code>Integer</code> 
     * @param endValue   The end value; should be of type <code>int</code> or <code>Integer</code> 
     * @return A linear interpolation between the start and end values, given the 
     *         <code>fraction</code> parameter. 
     */  
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {  
        int startInt = startValue;  
        return (int)(startInt + fraction * (endValue - startInt));  
    }  
} 

可以看到在 IntEvaluator 中只有一個函數(shù)(float fraction, Integer startValue, Integer endValue) ; 其中 fraction 就是加速器中的返回值,表示當前動畫的數(shù)值進度,百分制的小數(shù)表示。 startValue 和 endValue 分別對應(yīng) ofInt(int start,int end)中的 start 和 end 的數(shù)值; 比如我們假設(shè)當我們定義的動畫 ofInt(100,400)進行到數(shù)值進度 20%的時候,那么此時在 evaluate 函數(shù)中,fraction 的值就是 0.2,startValue 的值是 100,endValue 的值是 400;理解上應(yīng)該沒什么難度。 下面我們就來看看 evaluate(float fraction, Integer startValue, Integer endValue) 是如何根據(jù)進度小數(shù)值來計算出具體數(shù)字的:

return (int)(startInt + fraction * (endValue - startInt));

大家對這個公式是否似曾相識?我們前面提到的公式:

當前的值 = 100 + (400 - 100)* 顯示進度  

是不是與這個公式完全一樣?是的,絕逼完全一樣啊,計算原理我們在上面已經(jīng)講過了,而且根據(jù)進度來計算當前數(shù)字值本來就是這么算的…… 在我們看懂了 IntEvalutor 以后,下面我們嘗試自己寫一個 Evalutor

3、自定義 Evalutor

(1)、簡單實現(xiàn) MyEvalutor 前面我們看了 IntEvalutor 的代碼,我們仿照 IntEvalutor 的實現(xiàn)方法,我們自定義一個 MyEvalutor: 首先是實現(xiàn) TypeEvaluator 接口:

public class MyEvaluator implements TypeEvaluator<Integer> {  
    @Override  
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {  
        return null;  
    }  
}  

這里涉及到泛型的概念,不理解的同學可以去看看《夯實 JAVA 基本之一 —— 泛型詳解(1):基本使用》 在實現(xiàn) TypeEvaluator,我們給它指定它的返回是 Integer 類型,這樣我們就可以在 ofInt()中使用這個 Evaluator 了。再說一遍原因:只有定義動畫時的數(shù)值類型與 Evalutor 的返回值類型一樣時,才能使用這個 Evalutor;很顯然 ofInt()定義的數(shù)值類型是 Integer 而我們定義的 MyEvaluator,它的返回值類型也是 Integer;所以我們定義的 MyEvaluator 可以給 ofInt()來用。同理,如果我們把實現(xiàn)的 TypeEvaluator 填充為為 Float 類型,那么這個 Evalutor 也就只能給 FloatEvalutor 用了。 屁話了那么多,現(xiàn)在轉(zhuǎn)入正題,我們來簡單實現(xiàn) evaluate 函數(shù),代碼如下:

public class MyEvaluator implements TypeEvaluator<Integer> {  
    @Override  
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {  
        int startInt = startValue;  
        return (int)(200+startInt + fraction * (endValue - startInt));  
    }  
}  

我們在 IntEvaluator 的基礎(chǔ)上修改了下,讓它返回值時增加了 200;所以當我們定義的區(qū)間是 ofInt(0,400)時,它的實際返回值區(qū)間應(yīng)該是(200,600) 我們看看 MyEvaluator 的使用:

ValueAnimator animator = ValueAnimator.ofInt(0,400);  

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
    @Override  
    public void onAnimationUpdate(ValueAnimator animation) {  
        int curValue = (int)animation.getAnimatedValue();  
        tv.layout(tv.getLeft(),curValue,tv.getRight(),curValue+tv.getHeight());  
    }  
});  
animator.setDuration(1000);  
animator.setEvaluator(new MyEvaluator());  
animator.start(); 

設(shè)置 MyEvaluator 前的動畫效果:

http://wiki.jikexueyuan.com/project/android-animation/images/62.gif" alt="" />

然后再看看我們設(shè)置了 MyEvaluator 以后的效果:

http://wiki.jikexueyuan.com/project/android-animation/images/63.gif" alt="" />

很明顯,textview 的動畫位置都向下移動了 200 個點; 再重新看一下下面的這個流程圖:

http://wiki.jikexueyuan.com/project/android-animation/images/11.png" alt="" />

在加速器中,我們可以通過自定義加速器的返回的數(shù)值進度來改變返回數(shù)值的位置。比如上面我們實現(xiàn)的倒序動畫 在 Evaluator 中,我們又可以通過改變進度值所對應(yīng)的具體數(shù)字來改變數(shù)值的位置。 所以,結(jié)論來了: 我們可以通過重寫加速器改變數(shù)值進度來改變數(shù)值位置,也可以通過改變 Evaluator 中進度所對應(yīng)的數(shù)值來改變數(shù)值位置。

源碼在文章底部給出

下面我們就只通過重寫 Evaluator 來實現(xiàn)數(shù)值的倒序輸出; (2)、實現(xiàn)倒序輸出實例 我們自定義一個 ReverseEvaluator:

public class ReverseEvaluator implements TypeEvaluator<Integer> {  
    @Override  
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {  
        int startInt = startValue;  
        return (int) (endValue - fraction * (endValue - startInt));  
    }  
} 

其中 fraction * (endValue - startInt)表示動畫實際運動的距離,我們用 endValue 減去實際運動的距離就表示隨著運動距離的增加,離終點越來越遠,這也就實現(xiàn)了從終點出發(fā),最終運動到起點的效果了。 使用方法:

ValueAnimator animator = ValueAnimator.ofInt(0,400);  

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
    @Override  
    public void onAnimationUpdate(ValueAnimator animation) {  
        int curValue = (int)animation.getAnimatedValue();  
        tv.layout(tv.getLeft(),curValue,tv.getRight(),curValue+tv.getHeight());  
    }  
});  
animator.setDuration(1000);  
animator.setEvaluator(new ReverseEvaluator());  
animator.start(); 

效果圖:

http://wiki.jikexueyuan.com/project/android-animation/images/64.gif" alt="" />

源碼在文章底部給出

4、關(guān)于 ArgbEvalutor

1、使用 ArgbEvalutor 我們上面講了 IntEvaluator 和 FloatEvalutor,還說了 Evalutor 一般來講不能通用,會報強轉(zhuǎn)錯誤,也就是說,只有在數(shù)值類型相同的情況下,Evalutor 才能共用。 其實除了 IntEvaluator 和 FloatEvalutor,在 android.animation 包下,還有另外一個 Evalutor 叫 ArgbEvalutor。 ArgbEvalutor 是用來做顏色值過渡轉(zhuǎn)換的??赡苁枪雀璧拈_發(fā)人員覺得大家對顏色值變換可能并不知道要怎么做,所以特地給我們提供了這么一個過渡 Evalutor; 我們先來簡單看一下 ArgbEvalutor 的源碼:(這里先不做具體講解原理,最后會講原理,這里先會用)

public class ArgbEvaluator implements TypeEvaluator {  
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
        int startInt = (Integer) startValue;  
        int startA = (startInt >> 24);  
        int startR = (startInt >> 16) & 0xff;  
        int startG = (startInt >> 8) & 0xff;  
        int startB = startInt & 0xff;  

        int endInt = (Integer) endValue;  
        int endA = (endInt >> 24);  
        int endR = (endInt >> 16) & 0xff;  
        int endG = (endInt >> 8) & 0xff;  
        int endB = endInt & 0xff;  

        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))));  
    }  
}

我們在這里關(guān)注兩個地方,第一返回值是 int 類型,這說明我們可以使用 ofInt()來初始化動畫數(shù)值范圍。第二:顏色值包括 A,R,G,B 四個值,每個值是 8 位所以用 16 進制表示一個顏色值應(yīng)該是 0xffff0000(純紅色) 下面我們就使用一下 ArgbEvaluator,并看看效果:

ValueAnimator animator = ValueAnimator.ofInt(0xffffff00,0xff0000ff);  
animator.setEvaluator(new ArgbEvaluator());  
animator.setDuration(3000);  

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
    @Override  
    public void onAnimationUpdate(ValueAnimator animation) {  
        int curValue = (int)animation.getAnimatedValue();  
        tv.setBackgroundColor(curValue);  

    }  
});  

animator.start(); 

在這段代碼中,我們將動畫的數(shù)據(jù)范圍定義為(0xffffff00,0xff0000ff),即從黃色,變?yōu)樗{色。 在監(jiān)聽中,我們根據(jù)當前傳回來的顏色值,將其設(shè)置為 textview 的背景色 我們來看一下效果:

http://wiki.jikexueyuan.com/project/android-animation/images/65.gif" alt="" />

源碼在文章底部給出 到這里,我們就已經(jīng)知道 ArgbEvalutor 的使用方法和效果了,下面我們再來回頭看看 ArgbEvalutor 的實現(xiàn)方法

2、ArgbEvalutor 的實現(xiàn)原理 先重新看源碼:

/** 
 * This evaluator can be used to perform type interpolation between integer 
 * values that represent ARGB colors. 
 */  
public class ArgbEvaluator implements TypeEvaluator {  

    /** 
     * This function returns the calculated in-between value for a color 
     * given integers that represent the start and end values in the four 
     * bytes of the 32-bit int. Each channel is separately linearly interpolated 
     * and the resulting calculated values are recombined into the return value. 
     * 
     * @param fraction The fraction from the starting to the ending values 
     * @param startValue A 32-bit int value representing colors in the 
     * separate bytes of the parameter 
     * @param endValue A 32-bit int value representing colors in the 
     * separate bytes of the parameter 
     * @return A value that is calculated to be the linearly interpolated 
     * result, derived by separating the start and end values into separate 
     * color channels and interpolating each one separately, recombining the 
     * resulting values in the same way. 
     */  
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
        int startInt = (Integer) startValue;  
        int startA = (startInt >> 24);  
        int startR = (startInt >> 16) & 0xff;  
        int startG = (startInt >> 8) & 0xff;  
        int startB = startInt & 0xff;  

        int endInt = (Integer) endValue;  
        int endA = (endInt >> 24);  
        int endR = (endInt >> 16) & 0xff;  
        int endG = (endInt >> 8) & 0xff;  
        int endB = endInt & 0xff;  

        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))));  
    }  
}  

英文注釋的那一坨大家有興趣,可以看已看看,我這里就直接講代碼了 這段代碼分為三部分,第一部分根據(jù) startValue 求出其中 A,R,G,B 中各個色彩的初始值;第二部分根據(jù) endValue 求出其中 A,R,G,B 中各個色彩的結(jié)束值,最后是根據(jù)當前動畫的百分比進度求出對應(yīng)的數(shù)值 我們先來看第一部分:根據(jù) startValue 求出其中 A,R,G,B 中各個色彩的初始值

int startInt = (Integer) startValue;  
int startA = (startInt >> 24);  
int startR = (startInt >> 16) & 0xff;  
int startG = (startInt >> 8) & 0xff;  
int startB = startInt & 0xff;

這段代碼就是根據(jù)位移和與運算求出顏色值中 A,R,G,B 各個部分對應(yīng)的值;顏色值與 ARGB 值的對應(yīng)關(guān)系如下:

http://wiki.jikexueyuan.com/project/android-animation/images/12.png" alt="" />

所以我們的初始值是 0xffffff00,那么求出來的 startA = 0xff,startR = oxff,startG = 0xff,startB = 0x00; 關(guān)于通過位移和與運算如何得到指定位的值的問題,我就不再講了,大家如果不理解,可以搜一下相關(guān)運算符使用方法的文章。 同樣,我們看看第二部分根據(jù) endValue 求出其中 A,R,G,B 中各個色彩的結(jié)束值:

int endInt = (Integer) endValue;  
int endA = (endInt >> 24);  
int endR = (endInt >> 16) & 0xff;  
int endG = (endInt >> 8) & 0xff;  
int endB = endInt & 0xff;  

原理與 startValue 求 A,R,G,B 對應(yīng)值的一樣,所以對于我們上面例子中初始值 ofInt(0xffffff00,0xff0000ff)中的 endValue:0xff0000ff 所對應(yīng)的 endA = 0xff,endR = ox00;endG = 0x00;endB = 0xff; 最后一部分到了,就是如何根據(jù)進度來求得變化的值,我們先看看下面這句是什么意思:

startA + (int)(fraction * (endA - startA)))  

對于這個公式大家應(yīng)該很容易理解,與 IntEvaluator 中的計算公式一樣,就是根據(jù)透明度 A 的初始值、結(jié)束值求得當前進度下透明度 A 應(yīng)該的數(shù)值。 同理 startR + (int)(fraction (endR - startR)表示當前進度下的紅色值 startG + (int)(fraction (endG - startG))表示當前進度下的綠色值 startB + (int)(fraction * (endB - startB))表示當前進度下的藍色值 然后通過位移和或運算將當前進度下的 A,R,G,B 組合起來就是當前的顏色值了。

好了,到這里,有關(guān)加速器和 Evaluator 的知識就講完了,對于 ValueAnimator 還有一些知識沒來得及講,這篇文章已經(jīng)很長了,就另開一篇來講解吧

如果本文有幫到你,記得加關(guān)注哦

源碼下載地址:

csdn:http://download.csdn.net/detail/u013210620/9420356 github:https://github.com/harvic/BlogResForGitHub

請大家尊重原創(chuàng)者版權(quán),轉(zhuǎn)載請標明出處: http://blog.csdn.net/harvic880925/article/details/50546884 謝謝