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

    Kotlin

    dependencies {
        implementation("androidx.constraintlayout:constraintlayout:2.2.0-alpha13")
        // To use constraintlayout in compose
        implementation("androidx.constraintlayout:constraintlayout-compose:1.1.0-alpha13")
    }
    
  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> では、モーションを表現するさまざまな制約を定義します。この例では、モーションのエンドポイントごとに 1 つの <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> には、固有の属性が 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 の詳細については、次のリソースをご覧ください。