屬性動畫總覽

試用 Compose
Jetpack Compose 是 Android 推薦的 UI 工具包。瞭解如何在 Compose 中使用動畫。

屬性動畫系統是可靠的架構,可讓您為幾乎任何項目製作動畫。您可以定義動畫,隨著時間變更任何物件屬性。 檢查是否繪製在螢幕上屬性動畫會變更屬性的 (物件中的欄位) 值。如要為內容製作動畫,請指定 要加入動畫效果的物件屬性,例如物件在畫面上的位置、 要套用動畫效果 以及要套用動畫效果的值

屬性動畫系統可讓您定義動畫的下列特性:

  • 時間長度:您可以指定動畫的時間長度。預設長度為 300 毫秒。
  • 時間內插:您可以指定屬性值的計算方式 動畫目前的經過時間函式。
  • 重複計數和行為:您可以指定是否要在下列情況重複播放動畫: 動畫播放時間結束,以及重複播放動畫的次數。您也可以指定是否要讓動畫反向播放。將其設為反向播放,動畫會反覆向前播放,然後反向播放,直到達到重複播放次數為止。
  • 動畫師集:您可以將動畫分組為邏輯集,以便一起播放、依序播放或在指定延遲後播放。
  • 影格重新整理延遲時間:您可以指定重新整理動畫影格的頻率。預設值為每 10 毫秒重新整理一次,但應用程式重新整理影格速度最終取決於系統整體的繁忙程度,以及系統可服務基礎定時器的速度。

如要查看屬性動畫的完整範例,請參閱 CustomTransition 中的 ChangeColor 類別 範例。

屬性動畫的運作方式

首先,我們透過簡單的例子說明動畫的運作方式。圖 1 顯示了假設的物件,其動畫效果是使用 x 屬性,代表物件在螢幕上的水平位置。動畫時間長度設為 40 毫秒,距離 移動距離為 40 像素每 10 毫秒 (預設的影格刷新率) 都會移動物件一次 水平乘以 10 像素40 毫秒結束時,動畫會停止,物件則結束於 水平位置 40這個動畫範例採用線性內插類型 物件會以穩定速度移動

圖 1. 線性動畫範例

您也可以指定動畫採用非線性插補。圖 2 為假設物件,在動畫開始時加速,在動畫結束時減速。物件仍會在 40 毫秒內移動 40 個像素,但移動方式是非線性的。在 這個動畫一開始就加速至中點 直到動畫結束為止如圖 2 所示,移動的距離 出現在動畫開頭和結尾處都少於中間的長度。

圖 2. 非線性動畫範例

讓我們深入瞭解屬性動畫系統的重要元件如何計算上述動畫。圖 3 顯示主要類別如何相互運作。

圖 3. 動畫的計算方式

ValueAnimator 物件會追蹤動畫的時間,例如動畫已執行的時間長度,以及動畫所屬屬性的目前值。

ValueAnimator 封裝了 TimeInterpolator,用於定義動畫插補,以及 TypeEvaluator,用於定義如何計算要為動畫屬性計算的值。舉例來說,在圖 2 中,使用的 TimeInterpolator 會是 AccelerateDecelerateInterpolator,而 TypeEvaluator 會是 IntEvaluator

如要開始製作動畫,請建立 ValueAnimator 並為其提供 加入動畫後屬性的起始值和結束值,以及 動畫。呼叫 start() 時,動畫就會開始播放。在整個動畫播放期間,ValueAnimator 會計算經過的分數 介於 0 到 1 之間,根據動畫長度和經過的時間。經過的時間片段代表動畫完成的百分比,0 代表 0%,1 代表 100%。舉例來說,在圖 1 中,t = 10 毫秒時的已過時間片段為 .25,因為總時間長度為 t = 40 毫秒。

ValueAnimator 計算經過的分數時, 會呼叫目前設定的 TimeInterpolator,以便計算 內插分數。內插比例會將經過的分數對應至新的 的比例。例如,在圖 2 中 因為動畫的播放速度緩慢,因此內插分數 (約 0 .15) 低於 。在圖 1 中,內插分數一律與 所花費的分數

計算內插分數時,系統會呼叫 ValueAnimator 適當的 TypeEvaluator 來計算 您要加上動畫效果的屬性,取決於內插分數、起始值和 的結束值。例如,在圖 2 中,內插分數為 0 .15,而 t = 10 毫秒,此時的屬性值會是 .15 × (40 - 0) 或 6。

屬性動畫與檢視畫面動畫的差異

視圖動畫系統提供僅為 View 建立動畫的功能 因此,如果您想為非 View 物件建立動畫,就必須實作 導入您自己的程式碼另外,播放動畫系統也受到限制 公開 View 物件的幾個部分來製作動畫,例如縮放和 例如旋轉檢視畫面,而不是背景顏色

檢視區塊動畫系統的另一個缺點是只會在 此為繪製檢視畫面,而非實際的檢視畫面。舉例來說,如果您為按鈕製作動畫,讓它在畫面上移動,按鈕會正確繪製,但實際可點選按鈕的位置不會變更,因此您必須實作自己的邏輯來處理這項問題。

使用屬性動畫系統時,這些限制條件會完全移除,而您可以建立動畫。 任何物件的任何屬性 (View 和非 View) 以及物件本身,都會受到修改。 屬性動畫系統執行動畫的方式也更加完善。在 高階,您可以為每個要建立動畫的屬性指派動畫,例如顏色、 位置或大小,也可以定義動畫的各個元素,例如內插和大小 以便產生多個動畫

不過,View 動畫系統的設定時間較短,且需要編寫的程式碼較少。如果視圖動畫實現了您需要執行的所有動作,或現有程式碼是否已完成 可以達到您希望的效果,不需要使用屬性動畫系統。在某些情況下,您也許會想針對不同的情境使用兩種動畫系統。

API 總覽

您可以在 android.animation 中找到屬性動畫系統的大部分 API。由於檢視畫面動畫系統已在 android.view.animation 中定義許多內插器,因此您也可以在屬性動畫系統中使用這些內插器。下表說明屬性動畫系統的主要元件。

Animator 類別提供建立動畫的基本結構。您通常不會直接使用這個類別,因為它只會用到最少 才能完整支援動畫值。下列 子類別擴充 Animator

表 1. 動畫師

類別 說明
ValueAnimator 屬性動畫的主要時間引擎,同時會計算要為其製作動畫的屬性值。它包含所有用於計算動畫值的核心功能,並包含每個動畫的時間細節、動畫是否重複的資訊、接收更新事件的事件監聽器,以及設定要評估的自訂類型。為屬性加上動畫效果分為兩個部分:計算動畫 值,並在動畫的物件和屬性上設定這些值。「ValueAnimator」不會連出第二部分,所以你必須聆聽 更新 ValueAnimator 和 修改您要以自己的邏輯加入動畫的物件。請參閱 使用 ValueAnimator 製作動畫
ObjectAnimator ValueAnimator 的子類別,可讓您設定要加入動畫的目標物件和物件屬性。當這個類別計算動畫的新值時,就會相應更新屬性。您應在大多數情況下使用 ObjectAnimator,因為這可讓您更輕鬆地在目標物件上設定值的動畫。不過 由於 ObjectAnimator 還有一些限制 (例如規定必須明確限制),因此您有時候會想要直接使用 ValueAnimator 要存在於目標物件上的存取子方法。
AnimatorSet 提供將動畫組合成群組的機制 這兩個物件之間的關係您可以設定動畫同時播放、依序播放,或在指定延遲時間後播放。請參閱「Choreographing multiple 加入動畫集瞭解更多資訊

評估器會指示屬性動畫系統如何計算給定 資源。會使用 Animator 提供的時間資料 類別、動畫的開始和結束值,以及計算屬性的動畫值 根據這項資料屬性動畫系統提供下列評估工具:

表 2. 評估人員

類別/介面 說明
IntEvaluator 用於計算 int 屬性值的預設評估工具。
FloatEvaluator 用於計算 float 屬性值的預設評估工具。
ArgbEvaluator 用來計算以十六進制值表示的顏色屬性值的預設評估工具。
TypeEvaluator 可讓您建立自己的評估工具的介面。如果要建立動畫 「非」intfloat 或顏色的物件屬性; 您必須實作 TypeEvaluator 介面,以指定 計算物件屬性的動畫值。您也可以為 intfloat 和顏色指定自訂 TypeEvaluator 如果您想以不同方式處理這些型別,與預設行為不同。 詳情請參閱「使用 TypeEvaluator」一節 瞭解如何編寫自訂評估器。

時間內插器會定義如何計算動畫中的特定值,以時間為函數。舉例來說,您可以指定動畫在整個動畫中以線性方式發生,也就是動畫會在整個時間內均勻移動,也可以指定動畫使用非線性時間,例如在動畫開始時加速,在動畫結束時減速。表 3 說明 android.view.animation 中包含的插補器。如果提供的插補器都不符合您的需求,請實作 TimeInterpolator 介面並自行建立。如要進一步瞭解如何編寫自訂內插器,請參閱「使用內插器」一文。

表 3. 內插器

類別/介面 說明
AccelerateDecelerateInterpolator 內插器的變化速率開始和結束,但速度加快的內插器 中途
AccelerateInterpolator 變化速率一開始很慢,然後加快的插繪器。
AnticipateInterpolator 內插器,其變更會先從反向開始,再向前快速滑過。
AnticipateOvershootInterpolator 變換器的變更會先從反向開始,然後向前快速滑過並超過目標值,最後回到最終值。
BounceInterpolator 變更在結尾彈跳的內插器。
CycleInterpolator 內插器的動畫會依照指定循環次數重複播放。
DecelerateInterpolator 變化速率一開始很快的內插器 減速度。
LinearInterpolator 變化速率不變的內插器。
OvershootInterpolator 此內插器的內插器往前快速滑過並超過最終值,然後 應用程式。
TimeInterpolator 可讓您實作自有內插器的介面。

使用 ValueAnimator 製作動畫

ValueAnimator 類別可讓您為 您可以指定一組 intfloat 或顏色,藉此設定動畫的時間長度 產生動畫效果您可以藉由呼叫ValueAnimator 其工廠方法:ofInt()ofFloat()ofObject()。例如:

Kotlin

ValueAnimator.ofFloat(0f, 100f).apply {
    duration = 1000
    start()
}

Java

ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
animation.setDuration(1000);
animation.start();

在這個程式碼中,當 start() 方法執行時,ValueAnimator 會開始計算動畫的值 (介於 0 和 100 之間),持續時間為 1000 毫秒。

您也可以按照下列步驟指定要製作動畫的自訂類型:

Kotlin

ValueAnimator.ofObject(MyTypeEvaluator(), startPropertyValue, endPropertyValue).apply {
    duration = 1000
    start()
}

Java

ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();

在這段程式碼中,ValueAnimator 會開始計算 動畫,介於 startPropertyValueendPropertyValue 之間 start() 方法執行時,由 MyTypeEvaluator 提供的邏輯,持續 1000 毫秒。

只要新增 AnimatorUpdateListener 附加至 ValueAnimator 物件,如 下列程式碼:

Kotlin

ValueAnimator.ofObject(...).apply {
    ...
    addUpdateListener { updatedAnimation ->
        // You can use the animated value in a property that uses the
        // same type as the animation. In this case, you can use the
        // float value in the translationX property.
        textView.translationX = updatedAnimation.animatedValue as Float
    }
    ...
}

Java

animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
        // You can use the animated value in a property that uses the
        // same type as the animation. In this case, you can use the
        // float value in the translationX property.
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});

在「onAnimationUpdate()」中 方法中,您可以存取更新後的動畫值,並將其用於 其中一項資料檢視如要進一步瞭解事件監聽器,請參閱 動畫事件監聽器

使用 ObjectAnimator 製作動畫

ObjectAnimatorValueAnimator 的子類別 (請參閱上一節),結合了 ValueAnimator 的時間引擎和值運算,並具備為目標物件命名屬性設定動畫的功能。這樣一來,您就無須再實作 ValueAnimator.AnimatorUpdateListener,因為動畫屬性會自動更新,因此可讓您更輕鬆地為任何物件製作動畫。

ObjectAnimator 例項化與 ValueAnimator 類似,但您也必須指定物件和該物件屬性的名稱 (以字串格式),以及要加入動畫效果的值:

Kotlin

ObjectAnimator.ofFloat(textView, "translationX", 100f).apply {
    duration = 1000
    start()
}

Java

ObjectAnimator animation = ObjectAnimator.ofFloat(textView, "translationX", 100f);
animation.setDuration(1000);
animation.start();

取得 ObjectAnimator 更新屬性 就必須執行下列操作:

  • 您要製作動畫的物件屬性必須具有 setter 函式 (以駝峰式大小寫),格式為 set<PropertyName>()。由於 ObjectAnimator 會在動畫期間自動更新屬性,因此必須能夠透過此 setter 方法存取屬性。例如,如果屬性名稱為 foo,您必須 具有 setFoo() 方法如果找不到這個 setter 方法, 選項:
    • 如果您有權執行此操作,請將 setter 方法新增至類別。
    • 使用您有權變更的包裝函式類別,並讓該包裝函式透過有效的 setter 方法接收值,然後將其轉寄至原始物件。
    • 請改用 ValueAnimator
  • 如果您在其中一個 ObjectAnimator 工廠方法中只為 values... 參數指定一個值,系統會假設該參數為 因此,您要為動畫的物件屬性建立 getter 函式,用於取得動畫的起始值。Getter 函式必須採用 get<PropertyName>() 的形式。舉例來說,如果屬性名稱是 foo,您需要有 getFoo() 方法。
  • 您要建立動畫的屬性的 getter (如有需要) 和 setter 方法 會針對您指定 ObjectAnimator 的起始值和結束值使用相同的類型。舉例來說,您必須擁有 「targetObject.setPropName(float)」和「targetObject.getPropName()」 如果您建構以下 ObjectAnimator
    ObjectAnimator.ofFloat(targetObject, "propName", 1f)
  • 視您要製作動畫的屬性或物件而定,您可能需要在 View 上呼叫 invalidate() 方法,以便強制螢幕以已更新的動畫值重新繪製畫面。只要在 onAnimationUpdate() 回呼。舉例來說,為 Drawable 物件的色彩屬性加上動畫效果,只會更新 再次繪製該物件時的畫面。所有 View 屬性 setter (例如 setAlpha()setTranslationX()) 都會正確使 View 失效,因此您在呼叫這些方法時,不必將 View 設為無效,也不必傳入新的值。如要進一步瞭解事件監聽器,請參閱「動畫事件監聽器」一節。

使用 AnimatorSet 編排多個動畫

在許多情況下,您會希望播放的動畫取決於其他動畫的開始或結束時間。Android 系統可讓您將動畫組合成 AnimatorSet,以便指定是否要啟動動畫 依序或指定的延遲時間後你也可以為 AnimatorSet 物件建立巢狀結構。

以下程式碼片段會以以下方式播放下列 Animator 物件:

  1. 播放 bounceAnim
  2. 同時播放 squashAnim1squashAnim2stretchAnim1stretchAnim2
  3. 播放 bounceBackAnim
  4. 播放《fadeAnim》。

Kotlin

val bouncer = AnimatorSet().apply {
    play(bounceAnim).before(squashAnim1)
    play(squashAnim1).with(squashAnim2)
    play(squashAnim1).with(stretchAnim1)
    play(squashAnim1).with(stretchAnim2)
    play(bounceBackAnim).after(stretchAnim2)
}
val fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f).apply {
    duration = 250
}
AnimatorSet().apply {
    play(bouncer).before(fadeAnim)
    start()
}

Java

AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();

動畫事件監聽器

您可以在動畫播放期間透過下述的事件監聽器監聽重要事件。

您可以擴充 AnimatorListenerAdapter 類別, 實作 Animator.AnimatorListener 介面 (如果沒有的話) 想實作 Animator.AnimatorListener 的所有方法 存取 APIAnimatorListenerAdapter 類別提供空白 可以選擇覆寫的方法實作。

舉例來說,下列程式碼片段會為 onAnimationEnd() 回呼建立 AnimatorListenerAdapter

Kotlin

ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f).apply {
    duration = 250
    addListener(object : AnimatorListenerAdapter() {
        override fun onAnimationEnd(animation: Animator) {
            balls.remove((animation as ObjectAnimator).target)
        }
    })
}

Java

ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
    balls.remove(((ObjectAnimator)animation).getTarget());
}

為 ViewGroup 物件的版面配置變更製作動畫

屬性動畫系統提供為 ViewGroup 物件變更的動畫功能 並讓使用者輕鬆為 View 物件建立動畫

您可以利用 LayoutTransition 類別。當您將 View 新增至或從 ViewGroup 移除,或是使用 VISIBLEINVISIBLEGONE 呼叫 View 的 setVisibility() 方法時,ViewGroup 中的 View 會顯示和消失動畫。ViewGroup 中的其他 View 也可以 並在您新增或移除檢視畫面時,自動將物件加入新位置。您可以定義 以下 LayoutTransition 物件中的動畫 呼叫 setAnimator() 然後使用其中一個參數傳入 Animator 物件 下列 LayoutTransition 常數:

  • APPEARING - 此標記指出在以下項目上執行的動畫 。
  • CHANGE_APPEARING:此旗標會指出在容器中顯示新項目時,在變更項目上執行的動畫。
  • DISAPPEARING - 此標記指出在以下項目上執行的動畫 從容器中消失
  • CHANGE_DISAPPEARING - 此標記指出在下列項目上執行的動畫 而會隨著容器中的某個項目消失

您可以為這四種類型的事件定義自訂動畫,藉此自訂外觀 來設定版面配置轉場效果,或指示動畫系統使用預設動畫。

如要將 android:animateLayoutchanges 屬性設為 true, ViewGroup 可以執行以下動作:

<LinearLayout
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:id="@+id/verticalContainer"
    android:animateLayoutChanges="true" />

將此屬性設為 True 時,系統會自動為 ViewGroup 以及 ViewGroup 中的其他 View。

使用 StateListAnimator 為檢視畫面狀態變更加上動畫效果

StateListAnimator 類別可讓您定義在檢視畫面狀態變更時執行的動畫。這個物件會做為 Animator 物件的包裝函式,每當指定的檢視畫面狀態 (例如「按下」或「聚焦」) 發生變更時,就會呼叫該動畫。

StateListAnimator 可在 XML 資源中定義,其中包含根 <selector> 元素和子 <item> 元素,每個元素都會指定 StateListAnimator 類別定義的不同檢視畫面狀態。每項 <item> 包含屬性動畫集的定義。

舉例來說,下列檔案會建立狀態清單動畫,在按下時變更檢視畫面的 x 和 y 比例:

res/xml/animate_scale.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- the pressed state; increase x and y size to 150% -->
    <item android:state_pressed="true">
        <set>
            <objectAnimator android:propertyName="scaleX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1.5"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="scaleY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1.5"
                android:valueType="floatType"/>
        </set>
    </item>
    <!-- the default, non-pressed state; set x and y size to 100% -->
    <item android:state_pressed="false">
        <set>
            <objectAnimator android:propertyName="scaleX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="scaleY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1"
                android:valueType="floatType"/>
        </set>
    </item>
</selector>

如要將狀態清單動畫師附加至檢視畫面,請新增 android:stateListAnimator 屬性,如下所示:

<Button android:stateListAnimator="@xml/animate_scale"
        ... />

這個按鈕的狀態變更時,系統會使用 animate_scale.xml 中定義的動畫。

或者,您也可以改為使用 AnimatorInflater.loadStateListAnimator() 方法,將狀態清單動畫師指派給程式碼中的檢視畫面,然後使用 View.setStateListAnimator() 方法將動畫師指派給檢視畫面。

或者,您可以在兩個區域之間播放可繪項目動畫,而非為檢視區塊的屬性建立動畫。 狀態變更來使用 AnimatedStateListDrawable。 Android 5.0 中的部分系統小工具預設會使用這些動畫。以下範例說明 將 AnimatedStateListDrawable 定義為 XML 資源:

<!-- res/drawable/myanimstatedrawable.xml -->
<animated-selector
    xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- provide a different drawable for each state-->
    <item android:id="@+id/pressed" android:drawable="@drawable/drawableP"
        android:state_pressed="true"/>
    <item android:id="@+id/focused" android:drawable="@drawable/drawableF"
        android:state_focused="true"/>
    <item android:id="@id/default"
        android:drawable="@drawable/drawableD"/>

    <!-- specify a transition -->
    <transition android:fromId="@+id/default" android:toId="@+id/pressed">
        <animation-list>
            <item android:duration="15" android:drawable="@drawable/dt1"/>
            <item android:duration="15" android:drawable="@drawable/dt2"/>
            ...
        </animation-list>
    </transition>
    ...
</animated-selector>

使用 TypeEvaluator

如果您想為 Android 系統未知的類型製作動畫,可以實作 TypeEvaluator 介面,自行建立評估器。 Android 系統已知有 intfloat 或顏色 IntEvaluatorFloatEvaluatorArgbEvaluator 類型支援 我們會以驗證人員為審查目標。

TypeEvaluator 介面中,只有一個方法需要實作,即 evaluate() 方法。這樣一來,您使用的動畫師就能在動畫的目前點,為動畫屬性傳回適當的值。FloatEvaluator 類別示範如何執行這項操作:

Kotlin

private class FloatEvaluator : TypeEvaluator<Any> {

    override fun evaluate(fraction: Float, startValue: Any, endValue: Any): Any {
        return (startValue as Number).toFloat().let { startFloat ->
            startFloat + fraction * ((endValue as Number).toFloat() - startFloat)
        }
    }

}

Java

public class FloatEvaluator implements TypeEvaluator {

    public Object evaluate(float fraction, Object startValue, Object endValue) {
        float startFloat = ((Number) startValue).floatValue();
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
    }
}

注意:執行 ValueAnimator (或 ObjectAnimator) 時,系統會計算 動畫 (介於 0 和 1 之間的值),然後計算該動畫的內插版本 你使用的內插器規格內插分數就是 TypeEvaluator 透過 fraction 參數接收的資料,因此您可以 計算動畫值時也不必考量內插器。

使用內插器

內插器會定義如何計算動畫中的特定值,以時間為函數。舉例來說,您可以指定動畫在整個動畫中以線性方式發生,也就是動畫在整個時間內均勻移動,也可以指定動畫使用非線性時間,例如在動畫的開頭或結尾使用加速或減速。

動畫系統中的內插器會從動畫師接收代表動畫經過時間的部分值。內插器會修改這個分數,以符合 生成的圖片Android 系統會在 android.view.animation package 中提供一組常見的內插器。如果這些都不符合您的需求,您可以實作 TimeInterpolator 介面,並建立自己的介面。

以下範例比較預設插補器 AccelerateDecelerateInterpolatorLinearInterpolator 如何計算插補的部分。LinearInterpolator 對已經過的時間片段沒有任何影響。AccelerateDecelerateInterpolator 會加速進入動畫,並減速離開動畫。下列方法會定義這些插補器的邏輯:

AccelerateDecelerateInterpolator

Kotlin

override fun getInterpolation(input: Float): Float =
        (Math.cos((input + 1) * Math.PI) / 2.0f).toFloat() + 0.5f

Java

@Override
public float getInterpolation(float input) {
    return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}

LinearInterpolator

Kotlin

override fun getInterpolation(input: Float): Float = input

Java

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

下表列出這些插補器計算的近似值,適用於 1000 毫秒的動畫:

經過的毫秒 已經過的時間片段/插補時間片段 (線性) 內插的時間片段 (加速/減速)
0 0 0
200 20% .1
400 .4 0.345
600 0.6 .654
800 .8 0.9
1000 1 1

如表格所示,LinearInterpolator 會以相同的速度變更值,每 200 毫秒會變更 .2。AccelerateDecelerateInterpolator 會在 200 毫秒至 600 毫秒之間,變更超過 LinearInterpolator 的值,在 600 毫秒和 600 毫秒之間變化 1000 毫秒。

指定主要畫面格

Keyframe 物件包含時間/值組,可讓您在動畫的特定時間定義特定狀態。每個主要畫面格也可以有自己的內插器,用於控制前一個主要畫面格時間和這個主要畫面格時間之間的動畫行為。

如要將 Keyframe 物件例項化,您必須使用工廠方法之一 (ofInt()ofFloat()ofObject()) 取得適當類型的 Keyframe。接著,您撥打 將 ofKeyframe() 工廠方法 取得 PropertyValuesHolder 物件。取得物件後 取得動畫效果器,方法是傳入 PropertyValuesHolder 物件,並 要建立動畫的物件以下程式碼片段說明如何執行這項操作:

Kotlin

val kf0 = Keyframe.ofFloat(0f, 0f)
val kf1 = Keyframe.ofFloat(.5f, 360f)
val kf2 = Keyframe.ofFloat(1f, 0f)
val pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2)
ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation).apply {
    duration = 5000
}

Java

Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation);
rotationAnim.setDuration(5000);

以動畫呈現檢視畫面

屬性動畫系統可讓 View 物件動畫更流暢,並提供比 View 動畫系統更優異的優點。檢視畫面動畫系統會變更 View 物件的繪製方式,進而轉換 View 物件。這是 會在每個 View 的容器中處理,因為 View 本身並沒有可操作的屬性。 這會導致 View 產生動畫效果,但不會導致 View 物件本身發生變化。這會導致物件仍保留在原始位置的行為,即使物件是在螢幕上的不同位置繪製也一樣。在 Android 3.0 中,我們新增了新的屬性和對應的 getter 和 setter 方法,以消除這個缺點。

屬性動畫系統可以變更 View 物件中的實際屬性,為畫面上的 View 製作動畫。於 此外,View 也會自動呼叫 invalidate() 方法重新整理畫面。View 類別中用於顯示屬性動畫的新屬性:

  • translationXtranslationY:這些屬性可控制 檢視畫面以從左側和頂部座標設定的差異,由版面配置設定 都會在 Docker 容器中執行
  • rotationrotationXrotationY:這些屬性可控制 2D 中的旋轉 (rotation 屬性) 和 3D 中旋轉樞紐點的旋轉。
  • scaleXscaleY:這些屬性可控制 2D 縮放的 2D 縮放比例 以其樞紐點周圍檢視。
  • pivotXpivotY:這些屬性可控制 旋轉和縮放轉換的中心點根據預設 點位於物件的中心。
  • xy:這些簡單的公用程式屬性可用來描述 其容器中檢視畫面的最終位置, 列出左側和上方值的總和 TranslationX 和 translationY 值。
  • alpha:代表 View 的 Alpha 透明度。這個值預設為 1 (不透明),值為 0 則代表完全透明 (無法顯示)。

如要為 View 物件的屬性 (例如顏色或旋轉值) 建立動畫效果,您只需要 是建立屬性動畫工具 並指定想查看的資料檢視屬性 動畫。例如:

Kotlin

ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f)

Java

ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);

如需更多有關製作動畫的詳情,請參閱 動畫 ValueAnimatorObjectAnimator

使用 ViewPropertyAnimator 製作動畫

ViewPropertyAnimator 提供簡單的方式,可使用單一基礎 Animator 物件,平行為 View 的多個屬性製作動畫。它的行為與 ObjectAnimator 非常相似,因為它會修改檢視畫面屬性的實際值,但在一次為多個屬性加上動畫時,它的效率會更高。此外,使用 ViewPropertyAnimator 的程式碼也很大 更簡潔易讀下列程式碼片段顯示使用多個 ObjectAnimator 物件、單一 ObjectAnimatorViewPropertyAnimator 時,同時為檢視畫面中的 xy 屬性製作動畫的差異。

多個 ObjectAnimator 物件

Kotlin

val animX = ObjectAnimator.ofFloat(myView, "x", 50f)
val animY = ObjectAnimator.ofFloat(myView, "y", 100f)
AnimatorSet().apply {
    playTogether(animX, animY)
    start()
}

Java

ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();

One ObjectAnimator

Kotlin

val pvhX = PropertyValuesHolder.ofFloat("x", 50f)
val pvhY = PropertyValuesHolder.ofFloat("y", 100f)
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvhY).start()

Java

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvhY).start();

ViewPropertyAnimator

Kotlin

myView.animate().x(50f).y(100f)

Java

myView.animate().x(50f).y(100f);

如要進一步瞭解 ViewPropertyAnimator,請參閱對應的 Android 開發人員 網誌 貼文

在 XML 中宣告動畫

屬性動畫系統可讓您使用 XML 宣告屬性動畫,而非以程式輔助方式宣告。在 XML 中定義動畫,可輕鬆重複使用動畫 以更輕鬆的方式編輯動畫序列

為區分使用新屬性動畫 API 的動畫檔案,以及使用舊版檢視畫面動畫架構的動畫檔案,請從 Android 3.1 開始,將屬性動畫的 XML 檔案儲存在 res/animator/ 目錄中。

下列屬性動畫類別支援 XML 宣告,並使用下列 XML 標記:

如要查看可在 XML 宣告中使用的屬性,請參閱「動畫資源」。以下範例會依序播放兩組物件動畫,其中第一個巢狀集合會同時播放兩個物件動畫:

<set android:ordering="sequentially">
    <set>
        <objectAnimator
            android:propertyName="x"
            android:duration="500"
            android:valueTo="400"
            android:valueType="intType"/>
        <objectAnimator
            android:propertyName="y"
            android:duration="500"
            android:valueTo="300"
            android:valueType="intType"/>
    </set>
    <objectAnimator
        android:propertyName="alpha"
        android:duration="500"
        android:valueTo="1f"/>
</set>

如要執行此動畫,您必須將程式碼中的 XML 資源加載至 AnimatorSet 物件,然後設定所有動畫的目標物件 再開始播放動畫。為方便起見,呼叫 setTarget() 會設定一個用於 AnimatorSet 所有子項的目標物件。以下程式碼說明如何執行這項操作:

Kotlin

(AnimatorInflater.loadAnimator(myContext, R.animator.property_animator) as AnimatorSet).apply {
    setTarget(myObject)
    start()
}

Java

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

您也可以在 XML 中宣告 ValueAnimator,如以下範例所示:

<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:valueType="floatType"
    android:valueFrom="0f"
    android:valueTo="-100f" />

如要在程式碼中使用先前的 ValueAnimator,您必須 必須加載物件、 AnimatorUpdateListener, 取得更新後的動畫值,並用於其中一個檢視畫面的屬性 如以下程式碼所示:

Kotlin

(AnimatorInflater.loadAnimator(this, R.animator.animator) as ValueAnimator).apply {
    addUpdateListener { updatedAnimation ->
        textView.translationX = updatedAnimation.animatedValue as Float
    }

    start()
}

Java

ValueAnimator xmlAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(this,
        R.animator.animator);
xmlAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});

xmlAnimator.start();

如要瞭解定義屬性動畫的 XML 語法,請參閱「動畫資源」。

對 UI 效能可能造成的影響

更新 UI 的動畫會導致動畫執行時,每個影格都需要額外的轉譯作業。因此,使用耗用大量資源的動畫可能會對應用程式效能造成負面影響。

為 UI 加上動畫效果的工作會新增到以下項目的動畫階段: 算繪程序您可以啟用「Profile GPU Rendering」並監控動畫階段,瞭解動畫是否會影響應用程式的效能。詳情請參閱「剖析 GPU 轉譯功能的逐步操作說明」。