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

MotionLayout 是一種版面配置類型,可協助您管理應用程式中的動畫和小工具動畫。MotionLayoutConstraintLayout 的子類別,可利用其豐富的版面配置功能。在 ConstraintLayout 程式庫中,MotionLayout 可做為支援資料庫使用。

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.0-beta01"
        // To use constraintlayout in compose
        implementation "androidx.constraintlayout:constraintlayout-compose:1.1.0-beta01"
    }
    

    Kotlin

    dependencies {
        implementation("androidx.constraintlayout:constraintlayout:2.2.0-beta01")
        // To use constraintlayout in compose
        implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-beta01")
    }
    
  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 屬性參照了動作場景。動態場景是 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,請參閱下列資源: