天天看點

Android 三種動畫詳解

1 背景

不能隻分析源碼呀,分析的同時也要整理歸納基礎知識,剛好有人微網誌私信讓全面說說Android的動畫,是以今天來一發Android應用的各種Animation大集合。英文厲害的請直接移步參考Android Developer。

Android系統提供了很多豐富的API去實作UI的2D與3D動畫,最主要的劃分可以分為如下幾類:

View Animation: 視圖動畫在古老的Android版本系統中就已經提供了,隻能被用來設定View的動畫。

Drawable Animation: 這種動畫(也叫Frame動畫、幀動畫)其實可以劃分到視圖動畫的類别,專門用來一個一個的顯示Drawable的resources,就像放幻燈片一樣。

Property Animation: 屬性動畫隻對Android 3.0(API 11)以上版本的Android系統才有效,這種動畫可以設定給任何Object,包括那些還沒有渲染到螢幕上的對象。這種動畫是可擴充的,可以讓你自定義任何類型和屬性的動畫。

可以看見,目前應用程式開發涉及的主要動畫也就這三大類,我們接下來以類别為基礎來慢慢展開說明。

2 View Animation(視圖動畫)使用詳解

2-1 視圖動畫概述

視圖動畫,也叫Tween(補間)動畫可以在一個視圖容器内執行一系列簡單變換(位置、大小、旋轉、透明度)。譬如,如果你有一個TextView對象,您可以移動、旋轉、縮放、透明度設定其文本,當然,如果它有一個背景圖像,背景圖像會随着文本變化。

補間動畫通過XML或Android代碼定義,建議使用XML檔案定義,因為它更具可讀性、可重用性。

如下是視圖動畫相關的類繼承關系:

Android 三種動畫詳解
Android 三種動畫詳解

通過上圖和上表可以直覺的看出來補間動畫的關系及種類了吧,接下來我們就詳細一個一個的介紹一下各種補間動畫。

2-2 視圖動畫詳細說明

可以看出來Animation抽象類是所有補間動畫類的基類,是以基類會提供一些通用的動畫屬性方法,如下我們就來詳細看看這些屬性,關于這些屬性詳細官方解釋FQ點選我或者FQ點選我。

2-2-1 Animation屬性詳解

Android 三種動畫詳解

也就是說,無論我們補間動畫的哪一種都已經具備了這種屬性,也都可以設定使用這些屬性中的一個或多個。

那接下來我們就看看每種補間動畫特有的一些屬性說明吧。

Android 三種動畫詳解
Android 三種動畫詳解

2-2-6 AnimationSet詳解

AnimationSet繼承自Animation,是上面四種的組合容器管理類,沒有自己特有的屬性,他的屬性繼承自Animation,是以特别注意,當我們對set标簽使用Animation的屬性時會對該标簽下的所有子控件都産生影響。

2-3 視圖動畫使用方法

通過上面對于動畫的屬性介紹之後我們來看看在Android中這些動畫如何使用(PS:這裡直接示範xml方式,至于Java方式太簡單了就不說了),如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@[package:]anim/interpolator_resource"
    android:shareInterpolator=["true" | "false"] >
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float" />
    <scale
        android:fromXScale="float"
        android:toXScale="float"
        android:fromYScale="float"
        android:toYScale="float"
        android:pivotX="float"
        android:pivotY="float" />
    <translate
        android:fromXDelta="float"
        android:toXDelta="float"
        android:fromYDelta="float"
        android:toYDelta="float" />
    <rotate
        android:fromDegrees="float"
        android:toDegrees="float"
        android:pivotX="float"
        android:pivotY="float" />
    <set>
        ...
    </set>
</set>

ImageView spaceshipImage = (ImageView) findViewById(R.id.spaceshipImage);
Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);
spaceshipImage.startAnimation(hyperspaceJumpAnimation);
           

上面就是一個标準的使用我們定義的補間動畫的模闆。至于補間動畫的使用,Animation還有如下一些比較實用的方法介紹:

Android 三種動畫詳解

到此整個Android的補間動畫常用詳細屬性及方法全部介紹完畢,如有特殊的屬性需求可以通路Android Developer查閱即可。如下我們就來個綜合大演練。

2-4 視圖動畫注意事項

關于視圖動畫(補間動畫)的例子我就不介紹了,網上簡直多的都泛濫了。隻是強調在使用補間動畫時注意如下一點即可:

特别特别注意:補間動畫執行之後并未改變View的真實布局屬性值。切記這一點,譬如我們在Activity中有一個 Button在螢幕上方,我們設定了平移動畫移動到螢幕下方然後保持動畫最後執行狀态呆在螢幕下方,這時如果點選螢幕下方動畫執行之後的Button是沒 有任何反應的,而點選原來螢幕上方沒有Button的地方卻響應的是點選Button的事件。

2-5 視圖動畫Interpolator插值器詳解

2-5-1 插值器簡介

介紹補間動畫插值器之前我們先來看一幅圖,如下:

Android 三種動畫詳解

可以看見其實各種插值器都是實作了Interpolator接口而已,同時可以看見系統提供了許多已經實作OK的插值器,具體如下:

Android 三種動畫詳解

如上就是系統提供的一些插值器,下面我們來看看怎麼使用他們。

2-5-2 插值器使用方法

插值器的使用比較簡答,如下:

<set android:interpolator="@android:anim/accelerate_interpolator">
    ...
</set>
           

2-5-3 插值器的自定義

有時候你會發現系統提供的插值器不夠用,可能就像View一樣需要自定義。是以接下來我們來看看插值器的自定義,關于插值器的自定義分為兩種實作方式,xml自定義實作(其實就是對現有的插值器的一些屬性修改)或者java代碼實作方式。如下我們來說說。

先看看XML自定義插值器的步驟:

在res/anim/目錄下建立filename.xml檔案。

修改你準備自定義的插值器如下:

<?xml version="1.0" encoding="utf-8"?>
<InterpolatorName xmlns:android="http://schemas.android.com/apk/res/android"
    android:attribute_name="value"
    />

在你的補間動畫檔案中引用該檔案即可。
           

可以看見上面第二步修改的是現有插值器的一些屬性,但是有些插值器卻不具備修改屬性,具體如下:

無可自定義的attribute。

android:factor 浮點值,加速速率(預設值為1)。

android:tension 浮點值,起始點後拉的張力數(預設值為2)。

android:tension 浮點值,起始點後拉的張力數(預設值為2)。

android:extraTension 浮點值,拉力的倍數(預設值為1.5)。

無可自定義的attribute。

android:cycles 整形,循環的個數(預設為1)。

android:factor 浮點值,減速的速率(預設為1)。

無可自定義的attribute。

android:tension 浮點值,超出終點後的張力(預設為2)。

再來看看Java自定義插值器的(Java自定義插值器其實是xml自定義的更新,也就是說如果我們修改xml的屬性還不能滿足需求,那就可以選擇通過Java來實作)方式。

可以看見上面所有的Interpolator都實作了Interpolator接口,而Interpolator接口又繼承自 TimeInterpolator,TimeInterpolator接口定義了一個float getInterpolation(float input);方法,這個方法是由系統調用的,其中的參數input代表動畫的時間,在0和1之間,也就是開始和結束之間。

如下就是一個動畫始末速率較慢、中間加速的AccelerateDecelerateInterpolator插值器:

public class AccelerateDecelerateInterpolator extends BaseInterpolator
        implements NativeInterpolatorFactory {
    ......
    public float getInterpolation(float input) {
        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
    }
    ......
}
           

到此整個補間動畫與補間動畫的插值器都分析完畢了,接下來看下别的動畫。

3 Drawable Animation(Drawable動畫)使用詳解

3-1 Drawable動畫概述

Drawable動畫其實就是Frame動畫(幀動畫),它允許你實作像播放幻燈片一樣的效果,這種動畫的實質其實是Drawable,是以這種動畫的XML定義方式檔案一般放在res/drawable/目錄下。具體關于幀動畫的xml使用方式FQ點選我檢視,java方式FQ點選我檢視。

如下圖就是幀動畫的源碼檔案:

Android 三種動畫詳解

可以看見實際的真實父類就是Drawable。

3-2 Drawable動畫詳細說明

我們依舊可以使用xml或者java方式實作幀動畫。但是依舊推薦使用xml,具體如下:

必須是根節點,包含一個或者多個元素,屬性有:

android:oneshot true代表隻執行一次,false循環執行。
<item> 類似一幀的動畫資源。
           

animation-list的子項,包含屬性如下:

android:drawable 一個frame的Drawable資源。
android:duration 一個frame顯示多長時間。
           

3-3 Drawable動畫執行個體示範

關于幀動畫相對來說比較簡單,這裡給出一個正常使用架構,如下:

<!-- 注意:rocket.xml檔案位于res/drawable/目錄下 -->
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot=["true" | "false"] >
    <item
        android:drawable="@[package:]drawable/drawable_resource_name"
        android:duration="integer" />
</animation-list>

ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
rocketImage.setBackgroundResource(R.drawable.rocket_thrust);

rocketAnimation = (AnimationDrawable) rocketImage.getBackground();
rocketAnimation.start();
           

特别注意,AnimationDrawable的start()方法不能在Activity的onCreate方法中調運,因為AnimationDrawable還未完全附着到window上,是以最好的調運時機是onWindowFocusChanged()方法中。

至此幀動畫也就說明完成了。讓我們接下來進入Android更牛叉的動畫類型。

4 Property Animation(屬性動畫)使用詳解

在使用屬性動畫之前先來看幾個常用的View屬性成員:

translationX,translationY:控制View的位置,值是相對于View容器左上角坐标的偏移。
rotationX,rotationY:控制相對于軸心旋轉。
x,y:控制View在容器中的位置,即左上角坐标加上translationX和translationY的值。
alpha:控制View對象的alpha透明度值。
           

這幾個常用的屬性相信大家都很熟悉,接下來的屬性動畫我們就從這裡展開。

4-1 屬性動畫概述

Android 3.0以後引入了屬性動畫,屬性動畫可以輕而易舉的實作許多View動畫做不到的事,上面也看見了,View動畫無非也就做那幾種事情,别的也搞不定,而 屬性動畫就可以的,譬如3D旋轉一張圖檔。其實說白了,你記住一點就行,屬性動畫實作原理就是修改控件的屬性值實作的動畫。

具體先看下類關系:

/**
 * This is the superclass for classes which provide basic support for animations which can be
 * started, ended, and have <code>AnimatorListeners</code> added to them.
 */
public abstract class Animator implements Cloneable {
    ......
}
           

所有的屬性動畫的抽象基類就是他。我們看下他的實作子類:

Android 三種動畫詳解

其實可以看見,屬性動畫的實作有7個類(PS,之是以類繼承關系清單會出來那麼多是因為我下載下傳了所有版本的SDK,你隻用關注我紅點标注的就行,妹 的,ubuntu下圖檔處理工具怎麼都這麼難用),進去粗略分析可以發現,好幾個是hide的類,而其他可用的類繼承關系又如下:

Android 三種動畫詳解
Android 三種動畫詳解

是以可以看見,我們平時使用屬性動畫的重點就在于AnimatorSet、ObjectAnimator、TimeAnimator、ValueAnimator。是以接下來我們就來依次說說如何使用。

4-2 屬性動畫詳細說明

4-2-1 屬性動畫計算原理

參看Android官方文檔,英文原版詳情點我檢視!

Android屬性動畫(注意最低相容版本,不過可以使用開源項目來替代低版本問題)提供了以下屬性:

Duration:動畫的持續時間;
TimeInterpolation:定義動畫變化速率的接口,所有插值器都必須實作此接口,如線性、非線性插值器;
TypeEvaluator:用于定義屬性值計算方式的接口,有int、float、color類型,根據屬性的起始、結束值和插值一起計算出目前時間的屬性值;
Animation sets:動畫集合,即可以同時對一個對象應用多個動畫,這些動畫可以同時播放也可以對不同動畫設定不同的延遲;
Frame refreash delay:多少時間重新整理一次,即每隔多少時間計算一次屬性值,預設為10ms,最終重新整理時間還受系統程序排程與硬體的影響;
Repeat Country and behavoir:重複次數與方式,如播放3次、5次、無限循環,可以讓此動畫一直重複,或播放完時向反向播放;
           

接下來先來看官方為了解釋原理給出的兩幅圖(其實就是國中實體題,不解釋):

Android 三種動畫詳解

上面就是一個線性勻速動畫,描述了一個Object的X屬性運動動畫,該對象的X坐标在40ms内從0移動到40,每10ms重新整理一次,移動4次,每次移動為40/4=10pixel。 .

Android 三種動畫詳解

上面是一個非勻速動畫,描述了一個Object的X屬性運動動畫,該對象的X坐标在40ms内從0移動到40,每10ms重新整理一次,移動4次,但是速率不同,開始和結束的速度要比中間部分慢,即先加速後減速。

接下來我們來詳細的看一下,屬性動畫系統的重要組成部分是如何計算動畫值的,下圖描述了如上面所示動畫的實作作用過程。

Android 三種動畫詳解

其中的ValueAnimator是動畫的執行類,跟蹤了目前動畫的執行時間和目前時間下的屬性值;ValueAnimator封裝了動畫的 TimeInterpolator時間插值器和一個TypeEvaluator類型估值,用于設定動畫屬性的值,就像上面圖2非線性動畫 裡,TimeInterpolator使用了AccelerateDecelerateInterpolator、TypeEvaluator使用了 IntEvaluator。

為了執行一個動畫,你需要建立一個ValueAnimator,并且指定目标對象屬性的開始、結束值和持續時間。在調用start後,整個動畫過程 中, ValueAnimator會根據已經完成的動畫時間計算得到一個0到1之間的分數,代表該動畫的已完成動畫百分比。0表示0%,1表示100%,譬如上 面圖一線性勻速動畫中總時間 t = 40 ms,t = 10 ms的時候是 0.25。

當ValueAnimator計算完已完成動畫分數後,它會調用目前設定的TimeInterpolator,去計算得到一個 interpolated(插值)分數,在計算過程中,已完成動畫百分比會被加入到新的插值計算中。如上圖2非線性動畫中,因為動畫的運動是緩慢加速的, 它的插值分數大約是 0.15,小于t = 10ms時的已完成動畫分數0.25。而在上圖1中,這個插值分數一直和已完成動畫分數是相同的。

當插值分數計算完成後,ValueAnimator會根據插值分數調用合适的 TypeEvaluator去計算運動中的屬性值。

好了,現在我們來看下代碼就明白這段話了,上面圖2非線性動畫裡,TimeInterpolator使用了 AccelerateDecelerateInterpolator、TypeEvaluator使用了IntEvaluator。是以這些類都是标準的 API,我們來看下标準API就能類比自己寫了,如下:

首先計算已完成動畫時間分數(以10ms為例):t=10ms/40ms=0.25。

接着看如下源碼如何實作計算內插補點分數的:

public class AccelerateDecelerateInterpolator extends BaseInterpolator
        implements NativeInterpolatorFactory {
    public AccelerateDecelerateInterpolator() {
    }
    ......
    //這是我們關注重點,可以發現如下計算公式計算後(input即為時間因子)插值大約為0.15。
    public float getInterpolation(float input) {
        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
    }
    ......
}
           

其實AccelerateDecelerateInterpolator的基類接口就是TimeInterpolator,如下,他隻有getInterpolation方法,也就是上面我們關注的方法。

public interface TimeInterpolator {
    float getInterpolation(float input);
}
           

接着ValueAnimator會根據插值分數調用合适的TypeEvaluator(IntEvaluator)去計算運動中的屬性值,如下,因為startValue = 0,是以屬性值:0+0.15*(40-0)= 6。

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

這就是官方給的一個關于屬性動畫實作的過程及基本原了解釋,相信你看到這裡是會有些迷糊的,沒關系,你先有個大緻概念就行,接下來我們會慢慢進入實戰,因為Android的屬性動畫相對于其他動畫來說涉及的知識點本來就比較複雜,是以我們慢慢來。

4-2-2 XML方式屬性動畫

在xml中可直接用的屬性動畫節點有ValueAnimator、ObjectAnimator、AnimatorSet。如下是官方的一個例子和解釋(詳情點我):

<set
  android:ordering=["together" | "sequentially"]>

    <objectAnimator
        android:propertyName="string"
        android:duration="int"
        android:valueFrom="float | int | color"
        android:valueTo="float | int | color"
        android:startOffset="int"
        android:repeatCount="int"
        android:repeatMode=["repeat" | "reverse"]
        android:valueType=["intType" | "floatType"]/>

    <animator
        android:duration="int"
        android:valueFrom="float | int | color"
        android:valueTo="float | int | color"
        android:startOffset="int"
        android:repeatCount="int"
        android:repeatMode=["repeat" | "reverse"]
        android:valueType=["intType" | "floatType"]/>

    <set>
        ...
    </set>
</set>
           
Android 三種動畫詳解
<objectAnimator>屬性解釋:
同上<objectAnimator>屬性,不多介紹。
           

XML屬性動畫使用方法:

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
    R.animtor.property_animator);
set.setTarget(myObject);
set.start();
           

4-2-3 Java方式屬性動畫

1、ObjectAnimator:繼承自ValueAnimator,允許你指定要進行動畫的對象以及該對象 的一個屬性。該類會根據計算得到的新值自動更新屬性。大多數的情況使用ObjectAnimator就足夠了,因為它使得目标對象動畫值的處理過程變得足 夠簡單,不用像ValueAnimator那樣自己寫動畫更新的邏輯,但是ObjectAnimator有一定的限制,比如它需要目标對象的屬性提供指定 的處理方法(譬如提供getXXX,setXXX方法),這時候你就需要根據自己的需求在ObjectAnimator和ValueAnimator中看 哪種實作更友善了。

ObjectAnimator類提供了ofInt、ofFloat、ofObject這個三個常用的方法,這些方法都是設定動畫作用的元素、屬性、開始、結束等任意屬性值。當屬性值(上面方法的參數)隻設定一個時就把通過getXXX反射擷取的值作為起點,設定的值作為終點;如果設定兩個(參數),那麼一個是開始、另一個是結束。

特别注意:ObjectAnimator的動畫原理是不停的調用setXXX方法更新屬性值,所有使用ObjectAnimator更新屬性時的前提是Object必須聲明有getXXX和setXXX方法。

我們通常使用ObjectAnimator設定View已知的屬性來生成動畫,而一般View已知屬性變化時都會主動觸發重繪圖操作,是以動畫會自 動實作;但是也有特殊情況,譬如作用Object不是View,或者作用的屬性沒有觸發重繪,或者我們在重繪時需要做自己的操作,那都可以通過如下方法手 動設定:

ObjectAnimator mObjectAnimator= ObjectAnimator.ofInt(view, "customerDefineAnyThingName", 0,  1).setDuration(2000);
mObjectAnimator.addUpdateListener(new AnimatorUpdateListener()
        {
            @Override
            public void onAnimationUpdate(ValueAnimator animation)
            {
                //int value = animation.getAnimatedValue();  可以擷取目前屬性值
                //view.postInvalidate();  可以主動重新整理
                //view.setXXX(value);
                //view.setXXX(value);
                //......可以批量修改屬性
            }
        });
           

如下是一個我在項目中的Y軸3D旋轉動畫實作執行個體:

ObjectAnimator.ofFloat(view, "rotationY", 0.0f, 360.0f).setDuration(1000).start();
           

2、PropertyValuesHolder:多屬性動畫同時工作管理類。有時候我們需要同時修改多個屬性,那就可以用到此類,具體如下:

PropertyValuesHolder a1 = PropertyValuesHolder.ofFloat("alpha", 0f, 1f);  
PropertyValuesHolder a2 = PropertyValuesHolder.ofFloat("translationY", 0, viewWidth);  
......
ObjectAnimator.ofPropertyValuesHolder(view, a1, a2, ......).setDuration(1000).start();
           

如上代碼就可以實作同時修改多個屬性的動畫啦。

3、ValueAnimator:屬性動畫中的時間驅動,管理着動畫時間的開始、結束屬性值,相應時間屬性值計算方法等。包含所有計算動畫值的核心函數以及每一個動畫時間節點上的資訊、一個動畫是否重複、是否監聽更新事件等,并且還可以設定自定義的計算類型。

特别注意:ValueAnimator隻是動畫計算管理驅動,設定了作用目标,但沒有設定屬性,需要通過updateListener裡設定屬性才會生效。

ValueAnimator animator = ValueAnimator.ofFloat(0, mContentHeight);  //定義動畫
animator.setTarget(view);   //設定作用目标
animator.setDuration(5000).start();
animator.addUpdateListener(new AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation){
        float value = (float) animation.getAnimatedValue();
        view.setXXX(value);  //必須通過這裡設定屬性值才有效
        view.mXXX = value;  //不需要setXXX屬性方法
    }
});
           

大眼看上去可以發現和ObjectAnimator沒啥差別,實際上正是由于ValueAnimator不直接操作屬性值,是以要操作對象的屬性可以不需要setXXX與getXXX方法,你完全可以通過目前動畫的計算去修改任何屬性。

4、AnimationSet:動畫集合,提供把多個動畫組合成一個組合的機制,并可設定動畫的時序關系,如同時播放、順序播放或延遲播放。具體使用方法比較簡單,如下:

ObjectAnimator a1 = ObjectAnimator.ofFloat(view, "alpha", 1.0f, 0f);  
ObjectAnimator a2 = ObjectAnimator.ofFloat(view, "translationY", 0f, viewWidth);  
......
AnimatorSet animSet = new AnimatorSet();  
animSet.setDuration(5000);  
animSet.setInterpolator(new LinearInterpolator());   
//animSet.playTogether(a1, a2, ...); //兩個動畫同時執行  
animSet.play(a1).after(a2); //先後執行
......//其他組合方式
animSet.start();  
           

5、Evaluators相關類解釋: Evaluators就是屬性動畫系統如何去計算一個屬性值。它們通過Animator提供的動畫的起始和結束值去計算一個動畫的屬性值。

IntEvaluator:整數屬性值。

FloatEvaluator:浮點數屬性值。

ArgbEvaluator:十六進制color屬性值。

TypeEvaluator:使用者自定義屬性值接口,譬如對象屬性值類型不是int、float、color類型,你必須實作這個接口去定義自己的資料類型。
           

既然說到這了,那就來個例子吧,譬如我們需要實作一個自定義屬性類型和計算規則的屬性動畫,如下類型float[]:

ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(5000);
valueAnimator.setObjectValues(new float[2]); //設定屬性值類型
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setEvaluator(new TypeEvaluator<float[]>()
{
    @Override
    public float[] evaluate(float fraction, float[] startValue,
                            float[] endValue)
    {
        //實作自定義規則計算的float[]類型的屬性值
        float[] temp = new float[2];
        temp[0] = fraction * 2;
        temp[1] = (float)Math.random() * 10 * fraction;
        return temp;
    }
});

valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
    @Override
    public void onAnimationUpdate(ValueAnimator animation)
    {
        float[] xyPos = (float[]) animation.getAnimatedValue();
        view.setHeight(xyPos[0]);   //通過屬性值設定View屬性動畫
        view.setWidth(xyPos[1]);    //通過屬性值設定View屬性動畫
    }
});
           

6、Interpolators相關類解釋:

AccelerateDecelerateInterolator:先加速後減速。

AccelerateInterpolator:加速。

DecelerateInterpolator:減速。

AnticipateInterpolator:先向相反方向改變一段再加速播放。

AnticipateOvershootInterpolator:先向相反方向改變,再加速播放,會超出目标值然後緩慢移動至目标值,類似于彈簧回彈。

BounceInterpolator:快到目标值時值會跳躍。

CycleIinterpolator:動畫循環一定次數,值的改變為一正弦函數:Math.sin(2 * mCycles * Math.PI * input)。

LinearInterpolator:線性均勻改變。

OvershottInterpolator:最後超出目标值然後緩慢改變到目标值。

TimeInterpolator:一個允許自定義Interpolator的接口,以上都實作了該接口。
           

舉個例子,就像系統提供的标準API一樣,如下就是加速插值器的實作代碼,我們自定義時也可以類似實作:

//開始很慢然後不斷加速的插值器。
public class AccelerateInterpolator implements Interpolator {
    private final float mFactor;
    private final double mDoubleFactor;

    public AccelerateInterpolator() {
        mFactor = 1.0f;
        mDoubleFactor = 2.0;
    }

    ......

    //input  0到1.0。表示動畫目前點的值,0表示開頭,1表示結尾。
    //return  插值。值可以大于1超出目标值,也可以小于0突破低值。
    @Override
    public float getInterpolation(float input) {
        //實作核心代碼塊
        if (mFactor == 1.0f) {
            return input * input;
        } else {
            return (float)Math.pow(input, mDoubleFactor);
        }
    }
}
           

綜上可以發現,我們可以使用現有系統提供标準的東東實作屬性動畫,也可以通過自定義繼承相關接口實作自己的動畫,隻要實作上面提到的那些主要方法即可。

4-2-4 Java屬性動畫拓展之ViewPropertyAnimator動畫

在Android API 12時,View中添加了animate方法,具體如下:

public class View implements Drawable.Callback, KeyEvent.Callback,
        AccessibilityEventSource {
     ......
     /**
     * This method returns a ViewPropertyAnimator object, which can be used to animate
     * specific properties on this View.
     *
     * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View.
     */
    public ViewPropertyAnimator animate() {
        if (mAnimator == null) {
            mAnimator = new ViewPropertyAnimator(this);
        }
        return mAnimator;
    }
    ......
}
           

可以看見通過View的animate()方法可以得到一個ViewPropertyAnimator的屬性動畫(有人說他沒有繼承Animator類,是的,他是成員關系,不是之前那種繼承關系)。

ViewPropertyAnimator提供了一種非常友善的方法為View的部分屬性設定動畫(切記,是部分屬性),它可以直接使用一個 Animator對象設定多個屬性的動畫;在多屬性設定動畫時,它比 上面的ObjectAnimator更加牛逼、高效,因為他會管理多個屬性的invalidate方法統一調運觸發,而不像上面分别調用,是以還會有一些 性能優化。如下就是一個例子:

myView.animate().x(0f).y(100f).start();
           

4-2-5 Java屬性動畫拓展之LayoutAnimator容器布局動畫

Property動畫系統還提供了對ViewGroup中View添加時的動畫功能,我們可以用LayoutTransition對 ViewGroup中的View進行動畫設定顯示。LayoutTransition的動畫效果都是設定給ViewGroup,然後當被設定動畫的 ViewGroup中添加删除View時展現出來。該類用于目前布局容器中有View添加、删除、隐藏、顯示等時候定義布局容器自身的動畫和View的動 畫,也就是說當在一個LinerLayout中隐藏一個View的時候,我們可以自定義 整個由于LinerLayout隐藏View而改變的動畫,同時還可以自定義被隐藏的View自己消失時候的動畫等。

我們可以發現LayoutTransition類中主要有五種容器轉換動畫類型,具體如下:

LayoutTransition.APPEARING:當View出現或者添加的時候View出現的動畫。

LayoutTransition.CHANGE_APPEARING:當添加View導緻布局容器改變的時候整個布局容器的動畫。

LayoutTransition.DISAPPEARING:當View消失或者隐藏的時候View消失的動畫。

LayoutTransition.CHANGE_DISAPPEARING:當删除或者隐藏View導緻布局容器改變的時候整個布局容器的動畫。

LayoutTransition.CHANGE:當不是由于View出現或消失造成對其他View位置造成改變的時候整個布局容器的動畫。
           

XML方式使用系統提供的預設LayoutTransition動畫:

我們可以通過如下方式使用系統提供的預設ViewGroup的LayoutTransition動畫:

android:animateLayoutChanges=”true”

在ViewGroup添加如上xml屬性預設是沒有任何動畫效果的,因為前面說了,該動畫針對于ViewGroup内部東東發生改變時才有效,是以當我們設定如上屬性然後調運ViewGroup的addView、removeView方法時就能看見系統預設的動畫效果了。

還有一種就是通過如下方式設定:

android:layoutAnimation=”@anim/customer_anim”

通過這種方式就能實作很多吊炸天的動畫。

Java方式使用系統提供的預設LayoutTransition動畫:

在使用LayoutTransition時,你可以自定義這幾種事件類型的動畫,也可以使用預設的動畫,總之最終都是通過 setLayoutTransition(LayoutTransition lt)方法把這些動畫以一個LayoutTransition對象設定給一個ViewGroup。

譬如實作如上Xml方式的預設系統LayoutTransition動畫如下:

mTransitioner = new LayoutTransition();
mViewGroup.setLayoutTransition(mTransitioner);  
           

稍微再高端一點吧,我們來自定義這幾類事件的動畫,分别實作他們,那麼你可以像下面這麼處理:

mTransitioner = new LayoutTransition();

……

ObjectAnimator anim = ObjectAnimator.ofFloat(this, “scaleX”, 0, 1);

……//設定更多動畫

mTransition.setAnimator(LayoutTransition.APPEARING, anim);

……//設定更多類型的動畫 mViewGroup.setLayoutTransition(mTransitioner);

到此通過LayoutTransition你就能實作類似小米手機電腦切換普通型和科學型的炫酷動畫了。

5 Android動畫總結

到此Android動畫基本已經描述OK了,也就這麼三大類,尤其是屬性動畫更加一籌。但是特别說一句,上面基本都沒有提及到各種動畫的 Listener接口,原因是這個玩意太簡單,是以不提了,相信你會監聽View的onClickListener就一定會觸類旁通動畫的 Listener方法的。有了這些基礎相信無論是自定義控件時還是自定義動畫時都會起到直接的指導參考作用。其實對于Android的動畫實作遠遠不止現 在提到的這些,但是這些又是基礎,是以後面還會寫文章說說Android提供的其他動畫參考工具類的。

現在我們繼續沿用官方的對比,翻譯一下這些動畫的差別,具體如下(點我參看原文How Property Animation Differs from View Animation):

View動畫:

View動畫隻能夠為View添加動畫,如果想為非View對象添加動畫須自己實作;且View動畫支援的種類很少;尤其是他改變的是View的繪制效果,View的屬性沒有改變,其位置與大小都不變; View動畫代碼量少,使用簡單友善。

Property動畫:

彌補了View動畫的缺陷,你可以為一個對象的任意屬性添加動畫,對象自己的屬性會被真的改變;當對象的屬性變化的時候,屬性動畫會自動重新整理螢幕;屬性動畫改變的是對象的真實屬性,而且屬性動畫不止用于View,還可以用于任何對象。