使用轉場功能以動畫呈現版面配置變更

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

Android 的 轉換架構 可讓您為 提供起始和結束版面配置 你可以選擇所需的動畫類型,例如淡出檢視畫面 也可以變更檢視畫面大小 而轉換架構會決定 如何製作從起始版面配置到結束版面配置的動畫。

轉換架構包含下列功能:

  • 群組層級動畫: 將動畫效果套用至檢視區塊階層中的所有檢視畫面。
  • 內建動畫: 使用預先定義的動畫,呈現淡出或動作等常見效果。
  • 資源檔案支援: 從版面配置資源檔案載入檢視區塊階層和內建動畫。
  • 生命週期回呼: 接收可提供動畫和階層控制的回呼 變更程序

如需查看可在版面配置變更之間加入動畫效果的程式碼範例,請參閱 BasicTransition

在兩個版面配置之間建立動畫的基本程序如下:

  1. Scene 起始和結束版面配置不過,起始版面配置的場景是 通常是根據目前的版面配置自動決定。
  2. 建立 Transition 物件定義所需的動畫類型。
  3. 致電 TransitionManager.go()、 然後系統會執行動畫來替換版面配置

圖 1 中的圖表說明瞭版面配置之間的關係 場景、轉場和最終動畫

圖 1. 基本插圖 轉換架構如何產生動畫

建立場景

場景會儲存檢視區塊階層的狀態,包括其所有檢視區塊及其 屬性值。轉換架構可在起始點之間的動畫執行 以及結束場景

你可以透過版面配置建立場景 或從程式碼中的一組檢視畫面匯入資源檔案不過, 轉場的起點通常是從 。

場景也可以定義在變更場景時自動執行的動作。 如要在離開 GCP 後清除資料檢視設定 或轉換至場景

透過版面配置資源建立場景

您可以直接從版面配置資源建立 Scene 執行個體 檔案。如果檔案中的檢視區塊階層大部分為靜態,請使用這項技巧。 產生的場景代表您當時的檢視區塊階層狀態 已建立 Scene 執行個體。如果您變更了檢視區塊階層, 重新建立場景。架構會從整個檢視畫面建立場景 的階層無法透過版面配置檔案中的部分內容建立場景。

如要從版面配置資源檔案建立 Scene 例項,請擷取 版面配置的根層級 ViewGroup。接著,呼叫 Scene.getSceneForLayout()敬上 函式,其中包含場景根,以及版面配置檔案的資源 ID 包含場景的檢視區塊階層。

定義場景的版面配置

本節其餘部分的程式碼片段將說明如何建立 具有相同場景根元素的不同場景。這部分也示範 不必暗示可載入多個不相關的 Scene 物件 程序

這個範例包含下列版面配置定義:

  • 含有文字標籤和子項的活動主要版面配置 FrameLayout
  • ConstraintLayout 第一個場景,其中包含兩個文字欄位
  • 第二個場景的 ConstraintLayout,其中相同的兩個文字欄位 不同順序

此範例的設計目的是讓所有動畫都發生在子項中 活動主要版面配置的版面配置。主要版面配置中的文字標籤 保持靜態

活動的主要版面配置定義如下:

res/layout/activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/master_layout">
    <TextView
        android:id="@+id/title"
        ...
        android:text="Title"/>
    <FrameLayout
        android:id="@+id/scene_root">
        <include layout="@layout/a_scene" />
    </FrameLayout>
</LinearLayout>

此版面配置定義包含文字欄位和 FrameLayout 場景的根層級第一個場景的版面配置會包含在主要版面配置檔案中。 這樣一來,應用程式就能將其顯示為初始使用者介面的一部分,並載入 複製到場景中,因為架構只能將整個版面配置檔案載入 場景。

第一個場景的版面配置定義如下:

res/layout/a_scene.xml

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/scene_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    
    
</androidx.constraintlayout.widget.ConstraintLayout>

第二個場景的版面配置包含相同的兩個文字欄位, 相同的 ID—以不同的順序排列。定義如下:

res/layout/another_scene.xml

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/scene_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    
    
</androidx.constraintlayout.widget.ConstraintLayout>

透過版面配置產生場景

建立兩個限製版面配置的定義後,即可取得 個別場景。這樣就能在兩個使用者介面之間轉換 儲存空間設定 如要取得場景,您需要參照場景根目錄和版面配置 資源 ID

下列程式碼片段說明如何取得場景根目錄的參照, 從版面配置檔案建立兩個 Scene 物件:

Kotlin

val sceneRoot: ViewGroup = findViewById(R.id.scene_root)
val aScene: Scene = Scene.getSceneForLayout(sceneRoot, R.layout.a_scene, this)
val anotherScene: Scene = Scene.getSceneForLayout(sceneRoot, R.layout.another_scene, this)

Java

Scene aScene;
Scene anotherScene;

// Create the scene root for the scenes in this app.
sceneRoot = (ViewGroup) findViewById(R.id.scene_root);

// Create the scenes.
aScene = Scene.getSceneForLayout(sceneRoot, R.layout.a_scene, this);
anotherScene =
    Scene.getSceneForLayout(sceneRoot, R.layout.another_scene, this);

在應用程式中,現在有兩個 Scene 物件依據檢視畫面 階層這兩個場景都使用 res/layout/activity_main.xml 中的 FrameLayout 元素。

在程式碼中建立場景

您也可以在程式碼中建立 Scene 執行個體 ViewGroup 物件。修改檢視區塊階層時,請使用這項技巧 或動態產生程式碼時

如要在程式碼中從檢視區塊階層建立場景,請使用 Scene(sceneRoot, viewHierarchy)敬上 建構函式中設定。呼叫此建構函式就等同於呼叫 Scene.getSceneForLayout()敬上 函式。

下列程式碼片段說明如何建立 Scene 例項來自場景根元素和場景的檢視區塊階層 您的代碼:

Kotlin

val sceneRoot = someLayoutElement as ViewGroup
val viewHierarchy = someOtherLayoutElement as ViewGroup
val scene: Scene = Scene(sceneRoot, viewHierarchy)

Java

Scene mScene;

// Obtain the scene root element.
sceneRoot = (ViewGroup) someLayoutElement;

// Obtain the view hierarchy to add as a child of
// the scene root when this scene is entered.
viewHierarchy = (ViewGroup) someOtherLayoutElement;

// Create a scene.
mScene = new Scene(sceneRoot, mViewHierarchy);

建立場景動作

架構可讓您定義系統在何時執行自訂場景動作 進入或離開場景。在許多情況下,自訂場景動作的定義是 不需要執行其他操作,因為這個架構會為場景之間的變化建立動畫效果 。

場景動作很適合處理以下情況:

  • 為不在相同階層的檢視畫面加上動畫效果。你可以透過動畫 使用退出和進入場景動作建立開始和結束場景。
  • 如要為轉換架構無法自動加上動畫效果的檢視畫面加上動畫效果, 例如 ListView 物件如要 詳情請參閱「限制」一節。

如要提供自訂場景動作,請將動作定義為 Runnable 物件並傳遞至 Scene.setExitAction()。 或 Scene.setEnterAction() 函式。架構會在起始畫面呼叫 setExitAction() 函式 再執行轉場動畫和 setEnterAction() 函式。

套用轉場效果

轉換架構代表用 Transition 物件。您可以使用內建功能將 Transition 執行個體化 子類別 AutoTransitionFade,或 自行定義轉換過程。 接著,您就能執行 藉由傳遞結尾 SceneTransition TransitionManager.go()

轉換生命週期與活動生命週期類似,代表 架構會在起始點和 在重要的生命週期狀態中,架構會叫用 可讓您實作的回呼函式來調整使用者介面的顯示設定。 轉換的不同階段

建立轉場效果

上一節說明瞭如何建立代表 不同的檢視區塊階層定義開始和結束場景後 如要切換,請建立可以定義動畫的 Transition 物件。 架構可讓您指定資源檔案中的內建轉場效果 並在程式碼中加載,或建立內建轉場效果的執行個體 直接嵌入程式碼

表 1. 內建轉換類型。

類別 標記 效果
AutoTransition <autoTransition/> 預設轉場效果。系統會按照下列順序,在檢視畫面中淡出、移動和調整大小,以及淡出。
ChangeBounds <changeBounds/> 移動及調整檢視畫面大小。
ChangeClipBounds <changeClipBounds/> 擷取場景前後的 View.getClipBounds() 在轉換期間變更並套用這些變動的動畫效果。
ChangeImageTransform <changeImageTransform/> 擷取場景前後的 ImageView 矩陣 並在轉場期間為該元素加上動畫效果
ChangeScroll <changeScroll/> 擷取場景前後的目標捲動屬性 並為其套用動畫效果
ChangeTransform <changeTransform/> 擷取場景轉換前後的縮放及旋轉角度 並在轉場期間為這些變更加入動畫效果
Explode <explode/> 追蹤開始和結束內目標檢視畫面的瀏覽權限變更 並在場景邊緣內移動檢視畫面。
Fade <fade/> fade_in (觀看次數:) 下降。
fade_out 淡出觀看次數。
fade_in_out (預設) 會執行 fade_out,後面接著 fade_in
Slide <slide/> 追蹤開始和結束內目標檢視畫面的瀏覽權限變更 以及移動場景其中一側或向外移動檢視畫面。

從資源檔案建立轉換執行個體

這項技巧可讓您在不變更 活動的程式碼這個技巧也很適合用來區分 從應用程式程式碼的轉換定義,如相關章節所示 瞭解如何指定多個轉場效果

如要在資源檔案中指定內建轉場效果,請按照下列步驟操作:

  • 在專案中新增 res/transition/ 目錄。
  • 在這個目錄中建立新的 XML 資源檔案。
  • 為其中一項內建轉場效果新增 XML 節點。

舉例來說,下列資源檔案會指定 Fade 轉場效果:

res/transition/fade_transition.xml

<fade xmlns:android="http://schemas.android.com/apk/res/android" />

下列程式碼片段說明如何在內部加載 Transition 執行個體 擷取自資源檔案中的活動:

Kotlin

var fadeTransition: Transition =
    TransitionInflater.from(this)
                      .inflateTransition(R.transition.fade_transition)

Java

Transition fadeTransition =
        TransitionInflater.from(this).
        inflateTransition(R.transition.fade_transition);

在程式碼中建立轉換執行個體

如果您要以動態方式建立轉換物件, 修改程式碼中的使用者介面,並建立簡單的內建轉場效果 少量或完全沒有參數的執行個體

如要建立內建轉場效果的執行個體,請叫用 Transition 類別子類別中的建構函式。舉例來說, 下列程式碼片段會建立 Fade 轉換的執行個體:

Kotlin

var fadeTransition: Transition = Fade()

Java

Transition fadeTransition = new Fade();

套用轉場效果

您通常套用轉場效果,以便在不同的檢視區塊階層之間變更 回應事件 (例如使用者動作)。以搜尋應用程式為例: 當使用者輸入搜尋字詞並輕觸搜尋按鈕時,應用程式就會變更 並套用轉場效果 淡出搜尋按鈕,並讓搜尋結果淡出。

若需變更場景,同時回應事件來回應: 活動,呼叫 TransitionManager.go() 類別函式,結尾為 以及用於動畫的轉場效果執行個體,如 程式碼片段:

Kotlin

TransitionManager.go(endingScene, fadeTransition)

Java

TransitionManager.go(endingScene, fadeTransition);

架構會隨著檢視區塊變更場景根目錄中的檢視區塊階層 來自結束場景的階層結構 轉換執行個體。起始場景是 轉換。如果沒有先前的轉場效果,則會決定開始場景 自動從使用者介面目前的狀態自動存取

如果未指定轉換執行個體,轉換管理員可套用 對大多數情況而言,這是合理的轉換。適用對象 請參閱相關 API 參考資料 TransitionManager敬上 類別

選擇特定目標資料檢視

這個架構會在開始和結束場景中,為所有檢視畫面套用轉場效果 根據預設。在某些情況下,您可能只想將動畫套用至子集 特定場景的視野這套架構可讓你選取 動畫。舉例來說,該架構不支援 ListView 物件,因此請勿在轉場效果時為這些物件建立動畫。

轉換動畫的每個檢視畫面都稱為「目標」。只有在 在與場景相關聯的檢視區塊階層中選取目標。

如要從目標清單中移除一或多項資料檢視,請呼叫 removeTarget()敬上 方法,再開始轉換。如果只要把指定的資料檢視加進 只要建立目標清單 而是呼叫 addTarget()敬上 函式。如需詳細資訊,請參閱 Transition 類別。

指定多個轉場效果

為了讓動畫發揮最大影響力,請配合該動畫類型的變化類型 會發生什麼事舉例來說,移除部分資料檢視 動畫或淡入/淡出動畫效果 代表部分觀看次數已經無法使用。如果要將檢視表 建議您為移動中的各個點加入動畫效果 使用者就會注意到資料檢視的新位置。

您不必只選擇一個動畫,因為轉換架構 可讓您合併使用含有動畫效果的轉場效果組合 單獨的內建或自訂轉場效果

如要從 XML 的一組轉場效果定義轉場效果,請建立 資源檔案,並在 res/transitions/ 目錄中列出轉場效果 TransitionSet 元素。例如,下列程式碼片段說明如何 指定與 AutoTransition 具有相同行為的轉場效果集 類別:

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
    android:transitionOrdering="sequential">
    <fade android:fadingMode="fade_out" />
    <changeBounds />
    <fade android:fadingMode="fade_in" />
</transitionSet>

如要將轉場效果加載為 TransitionSet 物件位於 程式碼,呼叫 TransitionInflater.from()。 功能。TransitionSet 類別會從 Transition 類別,因此您可以將其與轉換管理員搭配使用 其他 Transition 執行個體。

套用沒有場景的轉場效果

變更檢視區塊階層並非修改使用者介面的唯一方法。個人中心 您也可以在 目前的階層

舉例來說,您可以使用 單一版面配置從顯示搜尋項目欄位和搜尋的版面配置開始 圖示。如要變更使用者介面以顯示結果,請移除搜尋按鈕 當使用者輕觸按鈕時呼叫 ViewGroup.removeView()敬上 函式並呼叫 ViewGroup.addView()。 函式。

如果替代方案是有兩個階層且 幾乎完全相同與其建立及維護兩個不同的版面配置檔案 只有在使用者介面出現細微差異時 您可以使用單一版面配置檔案 包含您在程式碼中修改的檢視區塊階層。

如果您是以這個方式在目前的檢視區塊階層中進行變更, 所以要建立場景可以改為建立及套用 使用延遲轉場,呈現檢視區塊階層的兩個狀態。這項功能 轉換架構會從目前的檢視區塊階層狀態開始,記錄 並套用轉場效果 變更。

如要在單一檢視區塊階層中建立延遲轉場效果,請按照下列步驟操作: 步驟:

  1. 在觸發轉換的事件時,呼叫 TransitionManager.beginDelayedTransition()敬上 函式,提供所有檢視區塊的上層檢視區塊 並使用要變更的轉場效果架構會儲存 子項檢視畫面的狀態及其屬性值。
  2. 根據您的用途,變更子項檢視畫面。架構 會記錄您對子資料檢視及相關屬性所做的變更。
  3. 系統根據您的變更重新繪製使用者介面時, 架構會為原始狀態與新狀態之間的變化建立動畫效果。

以下範例說明如何為文字檢視區塊新增動畫效果 透過延遲轉場效果套用階層結構第一個程式碼片段顯示版面配置 定義檔:

res/layout/activity_main.xml

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/mainLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <EditText
        android:id="@+id/inputText"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />
    ...
</androidx.constraintlayout.widget.ConstraintLayout>

下一個程式碼片段顯示動畫,以動畫方式新增文字檢視區塊:

MainActivity

Kotlin

setContentView(R.layout.activity_main)
val labelText = TextView(this).apply {
    text = "Label"
    id = R.id.text
}
val rootView: ViewGroup = findViewById(R.id.mainLayout)
val mFade: Fade = Fade(Fade.IN)
TransitionManager.beginDelayedTransition(rootView, mFade)
rootView.addView(labelText)

Java

private TextView labelText;
private Fade mFade;
private ViewGroup rootView;
...
// Load the layout.
setContentView(R.layout.activity_main);
...
// Create a new TextView and set some View properties.
labelText = new TextView(this);
labelText.setText("Label");
labelText.setId(R.id.text);

// Get the root view and create a transition.
rootView = (ViewGroup) findViewById(R.id.mainLayout);
mFade = new Fade(Fade.IN);

// Start recording changes to the view hierarchy.
TransitionManager.beginDelayedTransition(rootView, mFade);

// Add the new TextView to the view hierarchy.
rootView.addView(labelText);

// When the system redraws the screen to show this update,
// the framework animates the addition as a fade in.

定義轉換生命週期回呼

轉換生命週期與活動生命週期類似。代表 一種轉換狀態,架構會在呼叫之間的期間監控 加入 TransitionManager.go() 函式,並完成 動畫。在重要的生命週期狀態中,此架構會叫用回呼 由 TransitionListener 定義 存取 API

轉換生命週期回呼非常實用,例如複製檢視表時 從起始檢視區塊階層到結束檢視區塊階層的屬性值 換言之。不能直接將值從一開始的檢視畫面複製到 位於結束檢視區塊階層的檢視區塊階層,因為結束檢視區塊階層 提高作業效率。然而,您需要將 ,並在架構時複製到結束檢視區塊階層 已完成轉移。如要在轉換完成時收到通知 實作 TransitionListener.onTransitionEnd()敬上 功能。

如需詳細資訊,請參閱 TransitionListener敬上 類別

限制

本節列出轉換架構的部分已知限制:

  • 動畫套用至 SurfaceView可能未顯示 正確。SurfaceView 執行個體是從非 UI 執行緒更新,因此 更新可能不會與其他檢視畫面的動畫同步。
  • 某些特定的轉場效果可能無法產生您想要的動畫效果 僅適用於 TextureView 物件
  • 擴充的類別 AdapterView,例如 ListView 管理子項檢視畫面的方式 轉換架構如要嘗試根據 AdapterView 為檢視畫面建立動畫, 裝置螢幕可能會停止回應。
  • 如果您嘗試使用TextView 動畫,在物件完全完成前,文字會彈出新的位置 已調整大小。若要避免這個問題,請勿以動畫方式調整含有 文字。