使用 MotionLayout 管理動態和小工具動畫

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

MotionLayout 是一種版面配置類型,可協助您管理應用程式中的動作和小工具動畫。 MotionLayoutConstraintLayout 的子類別,並以其豐富的版面配置功能為基礎。MotionLayoutConstraintLayout 程式庫的一部分,以支援程式庫的形式提供。

MotionLayout 可彌合版面配置轉場效果與複雜動作處理之間的差距,提供介於屬性動畫架構TransitionManagerCoordinatorLayout 之間的混合功能。

圖 1. 透過觸控控制基本動作。

除了說明版面配置之間的轉場效果,MotionLayout 也可讓您為任何版面配置屬性製作動畫。此外,它也內建支援可搜尋的轉場效果。也就是說,您可以根據觸控輸入等條件,立即顯示轉場效果中的任何時間點。MotionLayout 也支援關鍵影格,可根據需求完全自訂轉場效果。

MotionLayout 全面支援宣告式機制,因此無論多麼複雜,您都可以用 XML 描述任何轉場效果。

設計須知

MotionLayout 的用途是移動、調整大小及製作動畫,適用於使用者互動的 UI 元素,例如按鈕和標題列。請勿在應用程式中使用動態效果做為無關的特殊效果。讓使用者瞭解應用程式的用途。如要進一步瞭解如何運用動態效果設計應用程式,請參閱 Material Design 專區的「瞭解動態效果」一節。

開始使用

請按照下列步驟,開始在專案中使用 MotionLayout

  1. 新增 ConstraintLayout 依附元件:如要在專案中使用 MotionLayout,請將 ConstraintLayout 2.0 依附元件新增至應用程式的 build.gradle 檔案。如果您使用 AndroidX,請新增下列依附元件:

    Groovy

    dependencies {
        implementation "androidx.constraintlayout:constraintlayout:2.2.1"
        // To use constraintlayout in compose
        implementation "androidx.constraintlayout:constraintlayout-compose:1.1.1"
    }

    Kotlin

    dependencies {
        implementation("androidx.constraintlayout:constraintlayout:2.2.1")
        // To use constraintlayout in compose
        implementation("androidx.constraintlayout:constraintlayout-compose:1.1.1")
    }
  2. 建立 MotionLayout 檔案: MotionLayoutConstraintLayout 的子類別,因此您可以將任何現有的 ConstraintLayout 轉換為 MotionLayout,方法是在版面配置資源檔案中取代類別名稱,如下列範例所示:

    AndroidX

    <!-- before: ConstraintLayout -->
    <androidx.constraintlayout.widget.ConstraintLayout .../>
    <!-- after: MotionLayout -->
    <androidx.constraintlayout.motion.widget.MotionLayout .../>
              

    支援資料庫

    <!-- before: ConstraintLayout -->
    <android.support.constraint.ConstraintLayout .../>
    <!-- after: MotionLayout -->
    <android.support.constraint.motion.MotionLayout .../>
              

    以下是 MotionLayout 檔案的完整範例,用於定義圖 1 所示的版面配置:

    AndroidX

    <?xml version="1.0" encoding="utf-8"?>
    <!-- activity_main.xml -->
    <androidx.constraintlayout.motion.widget.MotionLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/motionLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/scene_01"
        tools:showPaths="true">
    
        <View
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:background="@color/colorAccent"
            android:text="Button" />
    
    </androidx.constraintlayout.motion.widget.MotionLayout>
            

    支援資料庫

    <?xml version="1.0" encoding="utf-8"?>
    <!-- activity_main.xml -->
    <android.support.constraint.motion.MotionLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/motionLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/scene_01"
        tools:showPaths="true">
    
        <View
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:background="@color/colorAccent"
            android:text="Button" />
    
    </android.support.constraint.motion.MotionLayout>
            
  3. 建立 MotionScene:在先前的 MotionLayout 範例中,app:layoutDescription 屬性會參照 MotionScene。動態場景是 XML 資源檔案。在根元素 <MotionScene> 中,動態場景包含對應版面配置的所有動態說明。為將版面配置資訊與動作說明分開,每個 MotionLayout 都會參照個別的動作場景。動作場景中的定義會優先於 MotionLayout 中的任何類似定義。

    以下是動作場景檔案範例,說明圖 1 中的基本水平動作:

    <?xml version="1.0" encoding="utf-8"?>
    <MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:motion="http://schemas.android.com/apk/res-auto">
    
        <Transition
            motion:constraintSetStart="@+id/start"
            motion:constraintSetEnd="@+id/end"
            motion:duration="1000">
            <OnSwipe
                motion:touchAnchorId="@+id/button"
                motion:touchAnchorSide="right"
                motion:dragDirection="dragRight" />
        </Transition>
    
        <ConstraintSet android:id="@+id/start">
            <Constraint
                android:id="@+id/button"
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:layout_marginStart="8dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintStart_toStartOf="parent"
                motion:layout_constraintTop_toTopOf="parent" />
        </ConstraintSet>
    
        <ConstraintSet android:id="@+id/end">
            <Constraint
                android:id="@+id/button"
                android:layout_width="64dp"
                android:layout_height="64dp"
                android:layout_marginEnd="8dp"
                motion:layout_constraintBottom_toBottomOf="parent"
                motion:layout_constraintEnd_toEndOf="parent"
                motion:layout_constraintTop_toTopOf="parent" />
        </ConstraintSet>
    
    </MotionScene>
        

    注意事項:

    • <Transition> 包含動作的基本定義。

      • motion:constraintSetStartmotion:constraintSetEnd 是指動作的端點。這些端點會在稍後的動作場景中,以 <ConstraintSet> 元素定義。

      • motion:duration:指定動作完成所需的時間 (以毫秒為單位)。

    • <OnSwipe> 可讓你為動作建立觸控手勢。

      • motion:touchAnchorId 是指使用者可以滑動及拖曳的檢視區塊。

      • motion:touchAnchorSide 表示檢視區塊正從右側拖曳。

      • motion:dragDirection 是指拖曳的進度方向。舉例來說,motion:dragDirection="dragRight" 表示檢視畫面拖曳至右側時,進度會增加。

    • <ConstraintSet> 您可以在這裡定義各種限制,說明動作。 在本範例中,系統會為動作的每個端點定義一個 <ConstraintSet>。這些端點會使用 app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent" 垂直置中。水平方向的端點位於畫面最左側和最右側。

    如要進一步瞭解動作場景支援的各種元素,請參閱 MotionLayout 範例

插補屬性

在動態場景檔案中,ConstraintSet 元素可以包含在轉場期間插補的其他屬性。除了位置和界線,MotionLayout 還會插補下列屬性:

  • alpha
  • visibility
  • elevation
  • rotationrotationXrotationY
  • translationXtranslationYtranslationZ
  • scaleXscaleY

自訂屬性

<Constraint> 中,您可以使用 <CustomAttribute> 元素,為不單純與位置或 View 屬性相關的屬性指定轉場效果。

<Constraint
    android:id="@+id/button" ...>
    <CustomAttribute
        motion:attributeName="backgroundColor"
        motion:customColorValue="#D81B60"/>
</Constraint>

<CustomAttribute> 包含兩個自有屬性:

  • motion:attributeName 為必要項目,且必須與具有 getter 和 setter 方法的物件相符。getter 和 setter 必須符合特定模式。舉例來說,由於檢視畫面具有基礎 getBackgroundColor()setBackgroundColor() 方法,因此支援 backgroundColor
  • 您必須提供的其他屬性取決於值類型。請從下列支援類型中選擇:
    • motion:customColorValue 代表顏色
    • motion:customIntegerValue (整數)
    • motion:customFloatValue 浮點數
    • motion:customStringValue 字串
    • motion:customDimension 個維度
    • motion:customBoolean (布林值)

指定自訂屬性時,請在開始和結束 <ConstraintSet> 元素中定義端點值。

變更背景顏色

以上述範例為基礎,假設您希望檢視區塊的顏色隨著動作變化,如圖 2 所示。

圖 2. 檢視區塊移動時,背景顏色會隨之變化。

在每個 ConstraintSet 元素中新增 <CustomAttribute> 元素,如以下程式碼片段所示:

<ConstraintSet android:id="@+id/start">
    <Constraint
        android:id="@+id/button"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_marginStart="8dp"
        motion:layout_constraintBottom_toBottomOf="parent"
        motion:layout_constraintStart_toStartOf="parent"
        motion:layout_constraintTop_toTopOf="parent">
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#D81B60" />
    </Constraint>
</ConstraintSet>

<ConstraintSet android:id="@+id/end">
    <Constraint
        android:id="@+id/button"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_marginEnd="8dp"
        motion:layout_constraintBottom_toBottomOf="parent"
        motion:layout_constraintEnd_toEndOf="parent"
        motion:layout_constraintTop_toTopOf="parent">
        <CustomAttribute
            motion:attributeName="backgroundColor"
            motion:customColorValue="#9999FF" />
    </Constraint>
</ConstraintSet>

其他 MotionLayout 屬性

除了前述範例中的屬性外,MotionLayout 還有其他屬性可供指定:

  • app:applyMotionScene="boolean" 表示是否要套用動態場景。此屬性的預設值為 true
  • app:showPaths="boolean" 表示是否要在動作執行時顯示動作路徑。此屬性的預設值為 false
  • app:progress="float" 可讓您明確指定轉場進度。您可以使用從 0 (轉換開始) 到 1 (轉換結束) 的任何浮點值。
  • app:currentState="reference" 可讓您指定特定 ConstraintSet
  • app:motionDebug 可顯示動作的其他偵錯資訊。可能的值為 "SHOW_PROGRESS""SHOW_PATH""SHOW_ALL"

其他資源

如要進一步瞭解 MotionLayout,請參閱下列資源: