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

MotionLayout は、アプリ内のモーションとウィジェットのアニメーションを管理できるレイアウト タイプです。MotionLayoutConstraintLayout のサブクラスであり、その豊富なレイアウト機能を基礎としています。MotionLayoutConstraintLayout ライブラリに含まれるので、サポート ライブラリとして入手可能であり、API レベル 14 への下位互換性があります。

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

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

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

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

設計上の検討事項

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

スタートガイド

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

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

        dependencies {
            implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta1'
        }
            

    AndroidX を使用していない場合は、下記のサポート ライブラリの依存関係を追加します。

        dependencies {
            implementation 'com.android.support.constraint:constraint-layout:2.0.0-beta1'
        }
            
  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 属性は MotionScene を参照しています。MotionScene は、対応するレイアウトのモーションの記述をすべて含む XML リソース ファイルです。レイアウト情報とモーションの記述を分離しておくため、MotionLayout はそれぞれ別の MotionScene を参照します。MotionScene 内の定義は、MotionLayout 内の同様のどの定義よりも優先されます。

    図 1 の基本的な水平方向の動きを記述する MotionScene ファイルの例を次に示します。

        <?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 は、モーションの端点を示します。これらの端点は、MotionScene 内の後方の <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" により)垂直方向の中央に配置されます。水平方向の端点は、画面の左端と右端にあります。

    MotionScene でサポートされるさまざまな要素について詳しくは、MotionLayout の例をご覧ください。

補間される属性

MotionScene ファイル内では、遷移中に補間されるその他の属性を 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" は MotionScene を適用するかどうかを示します。この属性のデフォルト値は true です。
  • app:showPaths="boolean" は、モーションが実行されているときにモーション パスを表示するかどうかを示します。この属性のデフォルト値は false です。
  • app:progress="float" を使って、遷移の進行状況を明示的に指定できます。0(遷移の開始)から 1(遷移の終了)までの任意の浮動小数点値を使用できます。
  • app:currentState="reference" を使って特定の ConstraintSet を指定できます。
  • app:motionDebug を使ってモーションに関するその他のデバッグ情報を表示できます。指定可能な値は、「SHOW_PROGRESS」、「SHOW_PATH」、「SHOW_ALL」です。

参考情報

MotionLayout について詳しくは、以下のリンク先をご覧ください。