折りたたみ式デバイス用の設計

ConstraintLayout 2.1 リリースでは、折りたたみ式デバイスの管理に役立つ機能(SharedValuesReactiveGuide など)が追加され、MotionLayout でのアニメーションのサポートも強化されました。

共有される値

ConstraintLayout にランタイム値を挿入する新しいメカニズムを追加しました。これは、ConstraintLayout のすべてのインスタンスが値にアクセスできるため、システム全体の値に使用することを目的としています。

折りたたみ式デバイスのコンテキストでは、次のメカニズムを使用して、実行時に折りたたみの位置を挿入できます。

Kotlin

ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)

Java

ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold);

カスタム ヘルパーでは、変更に対するリスナーを追加することで、共有値にアクセスできます。

Kotlin

val sharedValues: SharedValues = ConstraintLayout.getSharedValues()
sharedValues.addListener(mAttributeId, this)

Java

SharedValues sharedValues = ConstraintLayout.getSharedValues();
sharedValues.addListener(mAttributeId, this);

FoldableExperiments の例では、Jetpack WindowManager ライブラリを使用して折りたたみの位置をキャプチャし、その位置を ConstraintLayout に挿入する方法を確認できます。

Kotlin

inner class StateContainer : Consumer<WindowLayoutInfo> {

    override fun accept(newLayoutInfo: WindowLayoutInfo) {

        // Add views that represent display features
        for (displayFeature in newLayoutInfo.displayFeatures) {
            val foldFeature = displayFeature as? FoldingFeature
            if (foldFeature != null) {
                if (foldFeature.isSeparating &&
                    foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL
                ) {
                    // The foldable device is in tabletop mode
                    val fold = foldPosition(motionLayout, foldFeature)
                    ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)
                } else {
                    ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, 0);
                }
            }
        }
    }
}

Java

class StateContainer implements Consumer<WindowLayoutInfo> {

    @Override
    public void accept(WindowLayoutInfo newLayoutInfo) {

        // Add views that represent display features
        for (DisplayFeature displayFeature : newLayoutInfo.getDisplayFeatures()) {
            if (displayFeature instanceof FoldingFeature) {
                FoldingFeature foldFeature = (FoldingFeature)displayFeature;
                if (foldFeature.isSeparating() &&
                    foldFeature.getOrientation() == FoldingFeature.Orientation.HORIZONTAL
                ) {
                    // The foldable device is in tabletop mode
                    int fold = foldPosition(motionLayout, foldFeature);
                    ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold);
                } else {
                    ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, 0);
                }
            }
        }
    }
}

fireNewValue() は、最初のパラメータとして値を表す ID と、2 番目のパラメータとして挿入する値を表す ID を受け取ります。

ReactiveGuide

コードを記述することなくレイアウトで SharedValue を利用する方法の 1 つは、ReactiveGuide ヘルパーを使用することです。これにより、リンクされた SharedValue に従って、水平または垂直のガイドラインが配置されます。

    <androidx.constraintlayout.widget.ReactiveGuide
        android:id="@+id/fold"
        app:reactiveGuide_valueId="@id/fold"
        android:orientation="horizontal" />

そうすれば、通常のガイドラインと同じように使用できます。

MotionLayout(折りたたみ式デバイスの場合)

2.1 の MotionLayout には、状態のモーフィングに役立ついくつかの機能を追加しました。これは、折りたたみ式デバイスでは通常、可能なレイアウト間でのアニメーション化を処理する必要があるため、特に有用な機能です。

折りたたみ式デバイスには、次の 2 つの方法があります。

  • 実行時に、現在のレイアウト(ConstraintSet)を更新して、折りたたみの表示と非表示を切り替えます。
  • サポートする折りたたみ式の状態(closedfoldedfully open)ごとに、個別の ConstraintSet を使用します。

ConstraintSet をアニメーション化する

MotionLayout の関数 updateStateAnimate() は 2.1 リリースで追加されました。

Kotlin

fun updateStateAnimate(stateId: Int, set: ConstraintSet, duration: Int)

Java

void updateStateAnimate(int stateId, ConstraintSet set, int duration);

この関数は、即時更新(updateState(stateId, constraintset) で可能)ではなく、特定の ConstraintSet の更新時に変更を自動的にアニメーション化します。これにより、折りたたみ式デバイスの現在の状態などの変更に応じて、その場で UI を更新できます。

MotionLayout 内の ReactiveGuide

ReactiveGuide は、MotionLayout 内で使用する場合に、次の 2 つの有用な属性もサポートします。

  • app:reactiveGuide_animateChange="true|false"

  • app:reactiveGuide_applyToAllConstraintSets="true|false"

最初のメソッドは、現在の ConstraintSet を変更し、その変更を自動的にアニメーション化します。2 つ目は、ReactiveGuide 位置の新しい値を MotionLayout 内のすべての ConstraintSet に適用します。折りたたみ式デバイスでの一般的なアプローチは、折りたたみ位置を表す ReactiveGuide を使用して、ReactiveGuide を基準としてレイアウト要素を設定することです。

複数の ConstraintSet を使用して折りたたみ式の状態を表す

折りたたみ式デバイスをサポートするように UI を設計するもう 1 つの方法は、現在の MotionLayout の状態を更新する代わりに、特定の個別の状態(closedfoldedfully open など)を作成することです。

このシナリオでは、引き続き ReactiveGuide を使用して折りたたみを表現することもできますが、各状態がどのように別の状態に移行するかについて、より細かく制御できます(現在の ConstraintSet を更新するときの自動アニメーションと比較した場合)。

この方法では、DeviceState リスナーの MotionLayout.transitionToState(stateId) メソッドで、MotionLayout が特定の状態に遷移するように単純に指示できます。