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

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

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

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

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

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

設計に関する注意事項

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

始める

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

  1. ConstraintLayout 依存関係を追加する: プロジェクトで MotionLayout を使用するには、アプリの build.gradle ファイルに ConstraintLayout 2.0 依存関係を追加します。AndroidX を使用している場合は、次の依存関係を追加します。

    GroovyKotlin
    dependencies {
        implementation
    "androidx.constraintlayout:constraintlayout:2.2.0-beta01"
       
    // To use constraintlayout in compose
        implementation
    "androidx.constraintlayout:constraintlayout-compose:1.1.0-beta01"
    }
    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 に変換できます。

    <!-- 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 ファイルの完全な例を次に示します。

    <?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 の詳細については、次のリソースをご覧ください。