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

高級(jí)進(jìn)階(一)

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

一、插值器

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

1、使用插值器

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

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

下面我們就來看一下利用 ValueAnimator 是如何實(shí)現(xiàn)的。布局和上一篇的都一樣,這里就不再細(xì)講了,我們著重來看一下,當(dāng)點(diǎ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 的位置,讓它跟著當(dāng)前動(dòng)畫的值來改變它當(dāng)前的 top 和 bottom 的位置。然后我們利用 setDuration(1000)給它設(shè)置上做一次動(dòng)畫所需要的時(shí)長,然后通過 setInterpolator()給它設(shè)置插值器,也就是過渡值變化的規(guī)則; 從效果圖中也可以看出,插值器的意義其實(shí)就相當(dāng)于物理公式中的加速度參數(shù),所以這也就是它也叫加速器的原因。 源碼在文章底部給出 在學(xué)會(huì)了怎么使用加速器以后,我們來看看如何自定義一個(gè)加速器吧

2、自定義加速器

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

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()就可以得到當(dāng)前的值; 那當(dāng)前的值是怎么來的呢?見下面的計(jì)算公式:(目前這么理解,后面會(huì)細(xì)講真實(shí)情況) 當(dāng)前的值 = 100 + (400 - 100) 顯示進(jìn)度 其中 100 和 400 就是我們?cè)O(shè)置的 ofInt(100,400)中的值,這個(gè)公式應(yīng)該是比較容易理解的,就相當(dāng)于我們做一個(gè)應(yīng)用題: 小明從 100 的位置開始出發(fā)向 400 的位置開始跑去,在走到全程距離 20%位置時(shí),請(qǐng)問小明在哪個(gè)數(shù)字點(diǎn)上? 當(dāng)前的值 = 100 + (400 -100) 0.2; 很簡單的應(yīng)用題,ofInt()中 AnimatorUpdateListener 中的當(dāng)前值就是這么來的。從這里大家可以看到,顯示進(jìn)度就表示的是當(dāng)前的值的位置。但由于我們可以通過指定 getInterpolation()的返回值來指定當(dāng)前的顯示值的進(jìn)度,所以隨著時(shí)間的增加,我們可以讓值隨意在我們想讓它在的位置。 再重復(fù)一遍,input 參數(shù)與任何我們?cè)O(shè)定的值沒關(guān)系,只與時(shí)間有關(guān),隨著時(shí)間的增長,動(dòng)畫的進(jìn)度也自然的增加,input 參數(shù)就代表了當(dāng)前動(dòng)畫的進(jìn)度。而返回值則表示動(dòng)畫的當(dāng)前數(shù)值進(jìn)度 通過上面我們應(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 值返回,即以當(dāng)前動(dòng)畫的進(jìn)度做為動(dòng)畫的數(shù)值進(jìn)度,這也就表示當(dāng)前動(dòng)畫的數(shù)值進(jìn)度與動(dòng)畫的時(shí)間進(jìn)度一致,比如,如果當(dāng)前動(dòng)畫進(jìn)度為 0,那動(dòng)畫的數(shù)值進(jìn)度也是 0,那如果動(dòng)畫進(jìn)度為 0.5,那動(dòng)畫的數(shù)值進(jìn)度也是在 0.5,當(dāng)動(dòng)畫結(jié)束,動(dòng)畫的進(jìn)度就變成 1 了,而動(dòng)畫的數(shù)值進(jìn)度也是 1 了。 下面我們就用一個(gè)例子來講一下如何自定義插值器。 2、示例 從上面的講解中也可以看到,我們自定義插值器,只需要實(shí)現(xiàn) TimeInterpolator 接口就可以了:

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

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

源碼在文章底部給出

二、Evaluator

1、概述

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

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

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

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

2、各種 Evaluator

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

但大家會(huì)說了,在此之前,我們?cè)谑褂?ofInt()時(shí),從來沒有給它定義過使用 IntEvaluator 來轉(zhuǎn)換值啊,那怎么也能正常運(yùn)行呢?因?yàn)?ofInt 和 ofFloat 都是系統(tǒng)直接提供的函數(shù),所以在使用時(shí)都會(huì)有默認(rèn)的加速器和 Evaluator 來使用的,不指定則使用默認(rèn)的;對(duì)于 Evaluator 而言,ofInt()的默認(rèn) Evaluator 當(dāng)然是 IntEvaluator;而 FloatEvalutar 默認(rèn)的則是 FloatEvalutor; 上面,我們已經(jīng)弄清楚 Evaluator 定義和使用方法,下面我們就來看看 IntEvaluator 內(nèi)部是怎么實(shí)現(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 中只有一個(gè)函數(shù)(float fraction, Integer startValue, Integer endValue) ; 其中 fraction 就是加速器中的返回值,表示當(dāng)前動(dòng)畫的數(shù)值進(jìn)度,百分制的小數(shù)表示。 startValue 和 endValue 分別對(duì)應(yīng) ofInt(int start,int end)中的 start 和 end 的數(shù)值; 比如我們假設(shè)當(dāng)我們定義的動(dòng)畫 ofInt(100,400)進(jìn)行到數(shù)值進(jìn)度 20%的時(shí)候,那么此時(shí)在 evaluate 函數(shù)中,fraction 的值就是 0.2,startValue 的值是 100,endValue 的值是 400;理解上應(yīng)該沒什么難度。 下面我們就來看看 evaluate(float fraction, Integer startValue, Integer endValue) 是如何根據(jù)進(jìn)度小數(shù)值來計(jì)算出具體數(shù)字的:

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

大家對(duì)這個(gè)公式是否似曾相識(shí)?我們前面提到的公式:

當(dāng)前的值 = 100 + (400 - 100)* 顯示進(jìn)度  

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

3、自定義 Evalutor

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

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

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

我們?cè)?IntEvaluator 的基礎(chǔ)上修改了下,讓它返回值時(shí)增加了 200;所以當(dāng)我們定義的區(qū)間是 ofInt(0,400)時(shí),它的實(shí)際返回值區(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 前的動(dòng)畫效果:

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

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

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

很明顯,textview 的動(dòng)畫位置都向下移動(dòng)了 200 個(gè)點(diǎn); 再重新看一下下面的這個(gè)流程圖:

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

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

源碼在文章底部給出

下面我們就只通過重寫 Evaluator 來實(shí)現(xiàn)數(shù)值的倒序輸出; (2)、實(shí)現(xiàn)倒序輸出實(shí)例 我們自定義一個(gè) 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)表示動(dòng)畫實(shí)際運(yùn)動(dòng)的距離,我們用 endValue 減去實(shí)際運(yùn)動(dòng)的距離就表示隨著運(yùn)動(dòng)距離的增加,離終點(diǎn)越來越遠(yuǎn),這也就實(shí)現(xiàn)了從終點(diǎn)出發(fā),最終運(yùn)動(dòng)到起點(diǎn)的效果了。 使用方法:

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

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

我們?cè)谶@里關(guān)注兩個(gè)地方,第一返回值是 int 類型,這說明我們可以使用 ofInt()來初始化動(dòng)畫數(shù)值范圍。第二:顏色值包括 A,R,G,B 四個(gè)值,每個(gè)值是 8 位所以用 16 進(jìn)制表示一個(gè)顏色值應(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(); 

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

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

源碼在文章底部給出 到這里,我們就已經(jīng)知道 ArgbEvalutor 的使用方法和效果了,下面我們?cè)賮砘仡^看看 ArgbEvalutor 的實(shí)現(xiàn)方法

2、ArgbEvalutor 的實(shí)現(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 中各個(gè)色彩的初始值;第二部分根據(jù) endValue 求出其中 A,R,G,B 中各個(gè)色彩的結(jié)束值,最后是根據(jù)當(dāng)前動(dòng)畫的百分比進(jìn)度求出對(duì)應(yīng)的數(shù)值 我們先來看第一部分:根據(jù) startValue 求出其中 A,R,G,B 中各個(gè)色彩的初始值

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

這段代碼就是根據(jù)位移和與運(yùn)算求出顏色值中 A,R,G,B 各個(gè)部分對(duì)應(yīng)的值;顏色值與 ARGB 值的對(duì)應(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)于通過位移和與運(yùn)算如何得到指定位的值的問題,我就不再講了,大家如果不理解,可以搜一下相關(guān)運(yùn)算符使用方法的文章。 同樣,我們看看第二部分根據(jù) endValue 求出其中 A,R,G,B 中各個(gè)色彩的結(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 對(duì)應(yīng)值的一樣,所以對(duì)于我們上面例子中初始值 ofInt(0xffffff00,0xff0000ff)中的 endValue:0xff0000ff 所對(duì)應(yīng)的 endA = 0xff,endR = ox00;endG = 0x00;endB = 0xff; 最后一部分到了,就是如何根據(jù)進(jìn)度來求得變化的值,我們先看看下面這句是什么意思:

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

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

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

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

源碼下載地址:

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

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