MotionLayout を使用してモーションとウィジェットのアニメーションを管理する

MotionLayout は、アプリ内のモーションとウィジェットのアニメーションを管理できるレイアウト タイプです。MotionLayoutConstraintLayout のサブクラスであり、その豊富なレイアウト機能を基礎としています。ConstraintLayout ライブラリの一部として、MotionLayout はサポート ライブラリとして使用できます。

MotionLayout はレイアウトの遷移と複雑なモーションの処理の橋渡しをしており、プロパティ アニメーション フレームワークTransitionManagerCoordinatorLayout の機能を合わせて提供します。

図 1.基本的なタップ操作のモーション。

MotionLayout を使用すると、レイアウト間の遷移を記述するだけでなく、レイアウト プロパティをアニメーション化できます。さらに、シーク可能な遷移ももともとサポートしています。それにより、タップ入力などのなんらかの条件に基づいて、遷移内の任意のポイントをすぐに表示することもできます。MotionLayout はキーフレームにも対応しており、必要に応じて完全にカスタマイズした遷移も可能です。

MotionLayout は完全に宣言型なので、どのような遷移も、どれほど複雑であっても、XML で記述することができます。

設計に関する注意事項

MotionLayout は、ボタンやタイトルバーなど、ユーザーが操作する UI 要素の移動、サイズ変更、アニメーション化を行うためのものです。アプリ内のモーションは、おまけの特殊効果として使用しないでください。アプリが何をしているかをユーザーに理解してもらうために使用します。モーションを含むアプリの設計について詳しくは、マテリアル デザインのモーションについてのセクションをご覧ください。

始める

プロジェクトで MotionLayout を使用する手順は次のとおりです。

  1. ConstraintLayout 依存関係を追加する: プロジェクトで MotionLayout を使用するには、アプリの build.gradle ファイルに ConstraintLayout 2.0 依存関係を追加します。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 のサブクラスであるため、下記の例に示すように、レイアウト リソース ファイル内のクラス名を置き換えることで、既存の ConstraintLayoutMotionLayout に変換できます。

    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 .../>
              

    図 1 に示すレイアウトを定義する MotionLayout ファイルの完全な例を次に示します。

    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> を 1 つずつ定義します。これらのエンドポイントは、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> には、固有の属性が 2 つあります。

  • motion:attributeName は必須で、ゲッター メソッドとセッター メソッドを持つオブジェクトと一致する必要があります。ゲッターとセッターは特定のパターンに一致する必要があります。たとえば、ビューには基礎になる 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 の詳細については、次のリソースをご覧ください。