「リストと詳細」レイアウトを作成する

リスト / 詳細は、2 つのペインで構成される UI パターンです。1 つのペインにはアイテムのリストが表示され、もう 1 つのペインにはリストから選択したアイテムの詳細が表示されます。

このパターンは、大規模なコレクションの要素に関する詳細情報を提供するアプリで特に便利です。たとえば、メールのリストと各メールメッセージの詳細なコンテンツを表示するメールクライアントなどです。 リストと詳細 / 詳細は、アプリの設定をカテゴリのリストに分割し、各カテゴリの設定を詳細ペインに表示するなど、重要度の低いパスにも使用できます。

リストページの横に表示される詳細ペイン。
図 1.画面サイズが十分な場合は、リストペインと並べて詳細 ペインが表示されます。
アイテムを選択すると、詳細ペインが画面全体に表示されます。
図 2.画面サイズが限られている場合は、アイテムが選択されているため、詳細ペインがスペース全体を占有します。

NavigableListDetailPaneScaffold を使用してリスト / 詳細パターンを実装する

NavigableListDetailPaneScaffold は、Jetpack Compose でリストと詳細レイアウトの実装を簡素化するコンポーザブルです。ListDetailPaneScaffold をラップし、組み込みのナビゲーションと予測型「戻る」アニメーションを追加します。

リストと詳細スキャフォールドは、最大 3 つのペインをサポートします。

  1. リストペイン: アイテムのコレクションを表示します。
  2. 詳細ペイン: 選択したアイテムの詳細を表示します。
  3. 追加ペイン(省略可): 必要に応じて追加のコンテキストを提供します。

スキャフォールドはウィンドウ サイズに基づいて調整されます。

  • 大きなウィンドウでは、リストペインと詳細ペインが並べて表示されます。
  • 小さなウィンドウでは、一度に 1 つのペインのみが表示され、ユーザーが移動すると切り替わります。

依存関係の宣言

NavigableListDetailPaneScaffold は、Material 3 アダプティブ ナビゲーション ライブラリの一部です。

次の 3 つの関連する依存関係をアプリまたはモジュールの build.gradle ファイルに追加します。

Kotlin

implementation("androidx.compose.material3.adaptive:adaptive")
implementation("androidx.compose.material3.adaptive:adaptive-layout")
implementation("androidx.compose.material3.adaptive:adaptive-navigation")

Groovy

implementation 'androidx.compose.material3.adaptive:adaptive'
implementation 'androidx.compose.material3.adaptive:adaptive-layout'
implementation 'androidx.compose.material3.adaptive:adaptive-navigation'
  • adaptive: HingeInfoPosture などの低レベルの構成要素
  • adaptive-layout: ListDetailPaneScaffoldSupportingPaneScaffold などのアダプティブ レイアウト
  • adaptive-navigation: ペイン内およびペイン間を移動するためのコンポーザブル。また、デフォルトでナビゲーションをサポートするアダプティブ レイアウト(NavigableListDetailPaneScaffoldNavigableSupportingPaneScaffold など)

プロジェクトに compose-material3-adaptive バージョン 1.1.0-beta1 以降が含まれていることを確認します。

予測型「戻る」ジェスチャーをオプトインする

Android 15 以前で予測型「戻る」アニメーションを有効にするには、予測型「戻る」ジェスチャーのサポートをオプトインする必要があります。オプトインするには、 android:enableOnBackInvokedCallback="true"<application> タグまたは 個々の <activity> タグに AndroidManifest.xml ファイル内で追加します。詳細については、予測型「戻る」ジェスチャーをオプトインするをご覧ください。

アプリが Android 16(API レベル 36)以降をターゲットにしている場合、予測型「戻る」はデフォルトで有効になります。

基本的な使用方法

次のように NavigableListDetailPaneScaffold を実装します。

  1. 選択したコンテンツを表すクラスを使用します。選択したリストアイテムの保存と復元をサポートするには、Parcelable クラスを使用します。 kotlin-parcelize プラグインを使用して、コードを生成します。
  2. rememberListDetailPaneScaffoldNavigator を使用して ThreePaneScaffoldNavigator を作成します。

このナビゲータは、リストペイン、詳細ペイン、追加ペイン間を移動するために使用されます。汎用型を宣言することで、ナビゲータはスキャフォールドの状態(つまり、どの MyItem が表示されているか)も追跡します。この型は Parcelable であるため、ナビゲータによって状態を保存して復元し、構成の変更を自動的に処理できます。

  1. ナビゲータを NavigableListDetailPaneScaffold コンポーザブルに渡します。

  2. NavigableListDetailPaneScaffold にリストペインの実装を提供します。AnimatedPane を使用して、 デフォルトのペイン アニメーションをナビゲーション中に適用します。次に、ThreePaneScaffoldNavigator を使用して詳細ペイン ListDetailPaneScaffoldRole.Detail に移動し、渡されたアイテムを表示します。

  3. 詳細ペインの実装を NavigableListDetailPaneScaffold に含めます。

ナビゲーションが完了すると、currentDestination には、アプリが移動したペイン(ペインに表示されるコンテンツを含む)が含まれます。contentKey プロパティは元の呼び出しで指定された型と同じであるため、表示に必要なデータにアクセスできます。

  1. 必要に応じて、NavigableListDetailPaneScaffolddefaultBackBehavior を変更します。デフォルトでは、NavigableListDetailPaneScaffolddefaultBackBehaviorPopUntilScaffoldValueChange を使用します。

アプリで別の「戻る」ナビゲーション パターンが必要な場合は、別の BackNavigationBehavior オプションを指定して、この動作をオーバーライドできます。

BackNavigationBehavior オプション

次のセクションでは、1 つのペインにメールのリスト、もう 1 つのペインに詳細ビューを表示するメールアプリの例を使用します。

この動作は、レイアウト構造全体の変更に重点を置いています。複数ペインの設定では、詳細ペインでメール コンテンツを変更しても、基盤となるレイアウト構造は変更されません。そのため、現在のコンテキスト内で元に戻すレイアウトの変更がないため、[戻る] ボタンを押すとアプリまたは現在のナビゲーション グラフが終了する可能性があります。単一ペイン レイアウトでは、[戻る] を押すと、詳細ビュー内のコンテンツの変更がスキップされ、リストビューに戻ります。これは明確なレイアウトの変更を表しているためです。

以下の例を考えてみましょう。

  • 複数ペイン: 詳細ペインにメール(アイテム 1)が表示されています。別のメール(アイテム 2)をクリックすると、詳細ペインが更新されますが、リストペインと詳細ペインは表示されたままになります。[戻る] を押すと、アプリまたは現在のナビゲーション フローが終了する可能性があります。
  • 単一ペイン: アイテム 1、アイテム 2 の順に表示し、[戻る] を押すと、メールリスト ペインに直接戻ります。

ユーザーが [戻る] アクションごとに明確なレイアウトの切り替えを認識できるようにする場合に使用します。

さまざまなレイアウト ペインでのナビゲーション値の変化を示すイラスト。
PopUntilContentChange

この動作では、表示されるコンテンツが優先されます。アイテム 1、アイテム 2 の順に表示した場合、[戻る] を押すと、レイアウトに関係なくアイテム 1 に戻ります。

以下の例を考えてみましょう。

  • 複数ペイン: 詳細ペインにアイテム 1 を表示し、リストでアイテム 2 をクリックします。詳細ペインが更新されます。[戻る] を押すと、詳細ペインがアイテム 1 に戻ります。
  • 単一ペイン: 同じコンテンツの復元が行われます。

ユーザーが [戻る] アクションで以前に表示したコンテンツに戻ることを想定している場合に使用します。

2 つの詳細ペイン間のトランジション
PopUntilCurrentDestinationChange

この動作では、現在のナビゲーション デスティネーションが変更されるまでバックスタックがポップされます。 これは、単一ペイン レイアウトと複数ペイン レイアウトの両方に適用されます。

以下の例を考えてみましょう。

単一ペイン レイアウトと複数ペイン レイアウトのどちらの場合でも、[戻る] を押すと、ハイライト表示されたナビゲーション要素から前のデスティネーションにフォーカスが移動します。メールアプリでは、選択したペインの視覚的な表示が切り替わります。

現在のナビゲーションの明確な視覚的表示を維持することがユーザー エクスペリエンスにとって重要な場合に使用します。

詳細ペインとリストペインの間を移動する
PopLatest

このオプションでは、バックスタックから最新のデスティネーションのみが削除されます。中間状態をスキップせずに戻るナビゲーションを行う場合は、このオプションを使用します。

これらのステップを実装すると、コードは次のようになります。

NavigableListDetailPaneScaffold(
    navigator = navigator,
    listPane = {
        AnimatedPane {
            ListContent(
                words = sampleWords,
                selectionState = navigator.currentDestination?.contentKey?.let {
                    SelectionVisibilityState.ShowSelection(it)
                } ?: SelectionVisibilityState.NoSelection,
                onWordClick = { word ->
                    scope.launch {
                        navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, word)
                    }
                },
                animatedVisibilityScope = this@AnimatedPane,
                sharedTransitionScope = this@SharedTransitionLayout
            )
        }
    },
    detailPane = {
        AnimatedPane {
            DetailContent(
                definedWord = navigator.currentDestination?.contentKey,
                animatedVisibilityScope = this@AnimatedPane,
                sharedTransitionScope = this@SharedTransitionLayout,
                onClosePane = {
                    scope.launch {
                        navigator.navigateBack(
                            backNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange
                        )

                    }
                }
            )
        }
    }