1. 程式人生 > >Android-動畫

Android-動畫

                 本文較長。。。時間充足可以看,沒時間的可以先收藏^_^

 

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

View Animation:

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

Drawable Animation:

                                    也叫Frame動畫、幀動畫。其實可以劃分到檢視動畫的類別,專門用來一個一個的顯示Drawable的resources,就像放幻燈片一樣。

Property Animation: 

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

 當前應用程式開發涉及的主要動畫也就這三大類,接下來就來詳細說一下這三種動畫。

View Animation(檢視動畫)

概述:檢視動畫,也叫補間動畫,可以在一個檢視容器內執行一系列簡單變換(位置、大小、旋轉、透明度)。比如我們有一個TextView物件,我們可以移動、旋轉、縮放、透明度設定其文字,如果它有一個背景影象,背景影象會隨著文字變化。

繼承關係:

java類名 xml關鍵字 描述資訊
AlphaAnimation <alpha> 放置在res/anim/目錄下 漸變透明度動畫效果
RotateAnimation <rotate> 放置在res/anim/目錄下 畫面轉移旋轉動畫效果
ScaleAnimation <scale> 放置在res/anim/目錄下 漸變尺寸伸縮動畫效果
TranslateAnimation <translate> 放置在res/anim/目錄下 畫面轉換位置移動動畫效果
AnimationSet <set> 放置在res/anim/目錄下 一個持有其它動畫元素alpha、scale、translate、rotate或者其它set元素的容器

詳細說明:Animation抽象類是所有補間動畫類的基類,所以基類會提供一些通用的動畫屬性方法。

屬性詳解:

xml屬性 java方法 解釋
android:detachWallpaper setDetachWallpaper(boolean) 是否在桌布上執行
android:duration setDuration(long) 動畫持續時間,毫秒為單位
android:fillAfter setFillAfter(boolean) 控制元件動畫結束時是否保持動畫最後的狀態
android:fillBefore setFillBefore(boolean) 控制元件動畫結束時是否還原到開始動畫前的狀態
android:fillEnabled setFillEnabled(boolean) 與android:fillBefore效果相同
android:interpolator setInterpolator(Interpolator) 設定插值器(指定的動畫效果,譬如回彈等)
android:repeatCount setRepeatCount(int) 重複次數
android:repeatMode setRepeatMode(int) 重複型別有兩個值,reverse表示倒序回放,restart表示從頭播放
android:startOffset setStartOffset(long) 呼叫start函式之後等待開始執行的時間,單位為毫秒
android:zAdjustment setZAdjustment(int) 表示被設定動畫的內容執行時在Z軸上的位置(top/bottom/normal),預設為normal

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

補間動畫特有屬性:

       通過上面對於動畫的屬性介紹之後我們來看看在Android中這些動畫如何使用。

.XML

<?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>

.JAVA

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

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

Animation類的方法 解釋
reset() 重置Animation的初始化
cancel() 取消Animation動畫
start() 開始Animation動畫
setAnimationListener(AnimationListener listener) 給當前Animation設定動畫監聽
hasStarted() 判斷當前Animation是否開始
hasEnded() 判斷當前Animation是否結束

既然補間動畫只能給View使用,那就來看看View中和動畫相關的幾個常用方法吧,如下:

View類的常用動畫操作方法 解釋
startAnimation(Animation animation) 對當前View開始設定的Animation動畫
clearAnimation() 取消當View在執行的Animation動畫

以上就是整個補間動畫常用的屬性的詳解和方法的介紹了,如果有特殊的屬性需求的話可以訪問Android Developer查閱。

Alpha屬性:

xml屬性 java方法 解釋
android:fromAlpha AlphaAnimation(float fromAlpha, …) 動畫開始的透明度(0.0到1.0,0.0是全透明,1.0是不透明)
android:toAlpha AlphaAnimation(…, float toAlpha) 動畫結束的透明度,同上


Rotate屬性:

xml屬性 java方法 解釋
android:fromDegrees RotateAnimation(float fromDegrees, …) 旋轉開始角度,正代表順時針度數,負代表逆時針度數
android:toDegrees RotateAnimation(…, float toDegrees, …) 旋轉結束角度,正代表順時針度數,負代表逆時針度數
android:pivotX RotateAnimation(…, float pivotX, …) 縮放起點X座標(數值、百分數、百分數p,譬如50表示以當前View左上角座標加50px為初始點、50%表示以當前View的左上角加上當前View寬高的50%做為初始點、50%p表示以當前View的左上角加上父控制元件寬高的50%做為初始點)
android:pivotY RotateAnimation(…, float pivotY) 縮放起點Y座標,同上規律


Scale屬性:

xml屬性 java方法 解釋
android:fromXScale ScaleAnimation(float fromX, …) 初始X軸縮放比例,1.0表示無變化
android:toXScale ScaleAnimation(…, float toX, …) 結束X軸縮放比例
android:fromYScale ScaleAnimation(…, float fromY, …) 初始Y軸縮放比例
android:toYScale ScaleAnimation(…, float toY, …) 結束Y軸縮放比例
android:pivotX ScaleAnimation(…, float pivotX, …) 縮放起點X軸座標(數值、百分數、百分數p,譬如50表示以當前View左上角座標加50px為初始點、50%表示以當前View的左上角加上當前View寬高的50%做為初始點、50%p表示以當前View的左上角加上父控制元件寬高的50%做為初始點)
android:pivotY ScaleAnimation(…, float pivotY) 縮放起點Y軸座標,同上規律


Translate屬性:

xml屬性 java方法 解釋
android:fromXDelta TranslateAnimation(float fromXDelta, …) 起始點X軸座標(數值、百分數、百分數p,譬如50表示以當前View左上角座標加50px為初始點、50%表示以當前View的左上角加上當前View寬高的50%做為初始點、50%p表示以當前View的左上角加上父控制元件寬高的50%做為初始點)
android:fromYDelta TranslateAnimation(…, float fromYDelta, …) 起始點Y軸從標,同上規律
android:toXDelta TranslateAnimation(…, float toXDelta, …) 結束點X軸座標,同上規律
android:toYDelta TranslateAnimation(…, float toYDelta) 結束點Y軸座標,同上規律

檢視動畫使用方法:

AnimationSet詳解:

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

檢視動畫注意事項:

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

檢視動畫Interpolator插值器

先看一張圖:

通過上圖我們可以看出來其實各種插值器都實現了Interpolator介面。同時也可以看見系統提供了很多插值器。

java類 xml id值 描述
AccelerateDecelerateInterpolator @android:anim/accelerate_decelerate_interpolator 動畫始末速率較慢,中間加速
AccelerateInterpolator @android:anim/accelerate_interpolator 動畫開始速率較慢,之後慢慢加速
AnticipateInterpolator @android:anim/anticipate_interpolator 開始的時候從後向前甩
AnticipateOvershootInterpolator @android:anim/anticipate_overshoot_interpolator 類似上面AnticipateInterpolator
BounceInterpolator @android:anim/bounce_interpolator 動畫結束時彈起
CycleInterpolator @android:anim/cycle_interpolator 迴圈播放速率改變為正弦曲線
DecelerateInterpolator @android:anim/decelerate_interpolator 動畫開始快然後慢
LinearInterpolator @android:anim/linear_interpolator 動畫勻速改變
OvershootInterpolator @android:anim/overshoot_interpolator 向前彈出一定值之後回到原來位置

上邊就是系統提供給我們的一些插值器。

插值器使用方法:

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

插值器的自定義:

       在使用插值器的時候我們會發現系統提供的插值器不夠用,就像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"
    />
  • 在你的補間動畫檔案中引用該檔案即可。

第二步修改的是現有插值器的一些屬性,但是有的插值器不具備修改屬性,比如:

<accelerateDecelerateInterpolator>

無可自定義的attribute。

<accelerateInterpolator>

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

<anticipateInterploator>

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

<anticipateOvershootInterpolator>

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

<bounceInterpolator>

無可自定義的attribute。

<cycleInterplolator>

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

<decelerateInterpolator>

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

<linearInterpolator>

無可自定義的attribute。

<overshootInterpolator>

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

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

 

以上就是整個補間動畫和它的插值器的介紹了。

 

Drawable Animation(Frame動畫、幀動畫

幀動畫概述:

      幀動畫允許我們實現像播放幻燈片一樣的效果,幀動畫的實質其實是Drawable,所以幀動畫的XML定義方式檔案一般放在res/drawable/目錄下。

原始碼:

Drawable動畫詳解:

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

<animation-list> 必須是根節點,包含一個或者多個<item>元素,屬性有:

  • android:oneshot true代表只執行一次,false迴圈執行。
  • <item> 類似一幀的動畫資源。

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

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

Drawable動畫例項演示:

  關於幀動畫相對來說比較簡單,寫一個常規使用框架,如下:

.XML

<!-- 注意: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>

.JAVA

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()方法中。

 

以上就是幀動畫了,比較簡單,接下來我們來說一說更牛逼的動畫型別~~~

 

Property Animation(屬性動畫)

 

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

  • translationX,translationY:控制View的位置,值是相對於View容器左上角座標的偏移。
  • rotationX,rotationY:控制相對於軸心旋轉。
  • x,y:控制View在容器中的位置,即左上角座標加上translationX和translationY的值。
  • alpha:控制View物件的alpha透明度值。

屬性動畫就是圍繞這幾個屬性來的。

屬性動畫概述:

       Android 3.0以後引入了屬性動畫,屬性動畫可以輕而易舉的實現許多View動畫做不到的事,通過上邊的介紹可以看出來View動畫的功能很low,只能做些簡單的操作,而我們的屬性動畫就可以去3D的旋轉一張圖片,為什麼呢?因為屬性動畫的實現原理就是通過修改控制元件的屬性來實現的動畫~

       上面也看見了,View動畫無非也就做那幾種事情,別的也搞不定,而屬性動畫就可以的,譬如3D旋轉一張圖片。其實說白了,你記住一點就行,屬性動畫實現原理就是修改控制元件的屬性值實現的動畫。

先來看一下類關係:

public abstract class Animator implements Cloneable {
  
}

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

AnimatorSet、FakeAnimator、ObjectAnimator、RenderNodeAnimator、RevealAnimator、TimeAnimator、ValueAnimator

可以看見,屬性動畫的實現有7個類(有很多類是因為下載了所有版本的SDK,只用看標註紅點的)進去粗略分析可以發現,好幾個是hide的類,而其他可用的類繼承關係又如下:

java類名 xml關鍵字 描述資訊
ValueAnimator <animator> 放置在res/animator/目錄下 在一個特定的時間裡執行一個動畫
TimeAnimator 不支援/點我檢視原因 時序監聽回撥工具
ObjectAnimator <objectAnimator> 放置在res/animator/目錄下 一個物件的一個屬性動畫
AnimatorSet <set> 放置在res/animator/目錄下 動畫集合

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

 

屬性動畫詳細說明

屬性動畫計算原理:

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

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

接下來看看官方解釋原理給的圖吧:

       上面就是一個線性勻速動畫,描述了一個Object的X屬性運動動畫,該物件的X座標在40ms內從0移動到40,每10ms重新整理一次,移動4次,每次移動為40/4=10pixel。 

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

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

 

其中的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的屬性動畫相對於其他動畫來說涉及的知識點本來就比較複雜,所以我們慢慢來。

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>

<set>屬性解釋:

xml屬性 解釋
android:ordering 控制子動畫啟動方式是先後有序的還是同時進行。sequentially:動畫按照先後順序;together(預設):動畫同時啟動;

<objectAnimator>屬性解釋:

xml屬性 解釋
android:propertyName String型別,必須要設定的節點屬性,代表要執行動畫的屬性(通過名字引用),闢如你可以指定了一個View的”alpha” 或者 “backgroundColor” ,這個objectAnimator元素沒有對外說明target屬性,所以你不能在XML中設定執行這個動畫,必須通過呼叫 loadAnimator()方法載入你的XML動畫資源,然後呼叫setTarget()應用到具備這個屬性的目標物件上(譬如TextView)。
android:valueTo float、int或者color型別,必須要設定的節點屬性,表明動畫結束的點;如果是顏色的話,由6位十六進位制的數字表示。
android:valueFrom 相對應valueTo,動畫的起始點,如果沒有指定,系統會通過屬性的get方法獲取,顏色也是6位十六進位制的數字表示。
android:duration 動畫的時長,int型別,以毫秒為單位,預設為300毫秒。
android:startOffset 動畫延遲的時間,從呼叫start方法後開始計算,int型,毫秒為單位。
android:repeatCount 一個動畫的重複次數,int型,”-1“表示無限迴圈,”1“表示動畫在第一次執行完成後重複執行一次,也就是兩次,預設為0,不重複執行。
android:repeatMode 重複模式:int型,當一個動畫執行完的時候應該如何處理。該值必須是正數或者是-1,“reverse”會使得按照動畫向相反的方向執行,可實現類似鐘擺效果。“repeat”會使得動畫每次都從頭開始迴圈。
android:valueType 關鍵引數,如果該value是一個顏色,那麼就不需要指定,因為動畫框架會自動的處理顏色值。有intType和floatType(預設)兩種:分別說明動畫值為int和float型。

<objectAnimator>屬性解釋: 
同上<objectAnimator>屬性,不多介紹。

XML屬性動畫使用方法:

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

以上就是XML實現屬性動畫了。

Java方式屬性動畫

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

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

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

通過以上的程式碼就可以實現同時修改多個屬性的動畫啦。

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方法,你完全可以通過當前動畫的計算去修改任何屬性。

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

Evaluators相關類解釋:

Evaluators就是屬性動畫系統如何去計算一個屬性值。它們通過Animator提供的動畫的起始和結束值去計算一個動畫的屬性值。

  • IntEvaluator:整數屬性值。

  • FloatEvaluator:浮點數屬性值。

  • ArgbEvaluator:十六進位制color屬性值。

  • TypeEvaluator:使用者自定義屬性值介面,譬如物件屬性值型別不是int、float、color型別,你必須實現這個介面去定義自己的資料型別。

舉個例子來實現一個自定義屬性型別和計算規則的屬性動畫:

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屬性動畫
    }
});

Interpolators相關類解釋:

  • AccelerateDecelerateInterolator:先加速後減速。

  • AccelerateInterpolator:加速。

  • DecelerateInterpolator:減速。

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

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

  • BounceInterpolator:快到目標值時值會跳躍。

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

  • LinearInterpolator:線性均勻改變。

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

  • TimeInterpolator:一個允許自定義Interpolator的介面,以上都實現了該介面。

舉個例子,寫一個加速插值器的程式碼:

//開始很慢然後不斷加速的插值器。
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);
        }
    }
}

       通過上邊的程式碼我們可以發現,通過系統給我們的標準的屬性就可以實現屬性動畫,我們也可以通過自定義屬性來實現我們所需要的屬性動畫只要實現主要方法就行啦。

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

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動畫:

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咱們就能實現類似小米手機計算器切換普通型和科學型的炫酷動畫了。

 

總結:

           這裡就是對動畫的基本描述已經差不多了,其實也就是三大類,但是屬性動畫更牛逼一點,但是上邊基本沒有提到各種動畫的Listener介面,因為這東西太簡單,如果你會監聽View的onClickListener就會觸類旁通動畫的Listener方法的。有了這些基礎,無論是自定義控制元件還是自定義動畫都會起到直接的參考作用,尤其是對於動畫這方面的實現遠遠不止現在提到的這些,這些只是東西,打好了基礎基礎才能讓未來更有建樹,加油~!