アダプティブ ナビゲーションを作成する

ほとんどのアプリには、アプリのメイン ナビゲーション UI からアクセスできる最上位のデスティネーションがいくつかあります。標準のスマートフォン ディスプレイなどのコンパクト ウィンドウでは、通常、デスティネーションはウィンドウの下部にあるナビゲーション バーに表示されます。タブレットの全画面アプリなど、拡大したウィンドウでは、通常、アプリの横にあるナビゲーション レールが適しています。デバイスの左右を持ちながらナビゲーション コントロールに簡単にアクセスできるためです。

NavigationSuiteScaffold は、WindowSizeClass に基づいて適切なナビゲーション UI コンポーザブルを表示することで、ナビゲーション UI 間の切り替えを簡素化します。これには、ランタイムのウィンドウ サイズ変更中に UI を動的に変更することも含まれます。デフォルトの動作では、次のいずれかの UI コンポーネントが表示されます。

  • 幅または高さがコンパクトな場合、またはデバイスがテーブルトップ モードの場合: ナビゲーション バー
  • その他のすべてのデバイス: ナビゲーション レール
図 1. NavigationSuiteScaffold は、コンパクト ウィンドウにナビゲーション バーを表示します。
図 2. NavigationSuiteScaffold は、拡大したウィンドウにナビゲーション レールを表示します。

依存関係を追加する

NavigationSuiteScaffoldMaterial3 適応型ナビゲーション スイート ライブラリの一部です。アプリまたはモジュールの build.gradle ファイルにライブラリの依存関係を追加します。

Kotlin

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

Groovy

implementation 'androidx.compose.material3:material3-adaptive-navigation-suite'

スキャフォールドを作成する

NavigationSuiteScaffold の 2 つの主な部分は、ナビゲーション スイート アイテムと、選択したリンク先のコンテンツです。ナビゲーション スイート アイテムはコンポーザブルで直接定義できますが、他の場所(列挙型など)で定義するのが一般的です。

enum class AppDestinations(
    @StringRes val label: Int,
    val icon: ImageVector,
    @StringRes val contentDescription: Int
) {
    HOME(R.string.home, Icons.Default.Home, R.string.home),
    FAVORITES(R.string.favorites, Icons.Default.Favorite, R.string.favorites),
    SHOPPING(R.string.shopping, Icons.Default.ShoppingCart, R.string.shopping),
    PROFILE(R.string.profile, Icons.Default.AccountBox, R.string.profile),
}

NavigationSuiteScaffold を使用するには、現在のデスティネーションをトラッキングする必要があります。これは rememberSaveable を使用して行えます。

var currentDestination by rememberSaveable { mutableStateOf(AppDestinations.HOME) }

次の例では、navigationSuiteItems パラメータ(型 NavigationSuiteScope)が item 関数を使用して、個々のデスティネーションのナビゲーション UI を定義します。デスティネーション UI は、ナビゲーション バー、レール、ドロワー全体で使用されます。ナビゲーション アイテムを作成するには、AppDestinations(上のスニペットで定義)をループします。

NavigationSuiteScaffold(
    navigationSuiteItems = {
        AppDestinations.entries.forEach {
            item(
                icon = {
                    Icon(
                        it.icon,
                        contentDescription = stringResource(it.contentDescription)
                    )
                },
                label = { Text(stringResource(it.label)) },
                selected = it == currentDestination,
                onClick = { currentDestination = it }
            )
        }
    }
) {
    // TODO: Destination content.
}

宛先コンテンツ ラムダ内で、currentDestination 値を使用して、表示する UI を決定します。アプリでナビゲーション ライブラリを使用している場合は、ここで適切なデスティネーションを表示します。when ステートメントで十分な場合:

NavigationSuiteScaffold(
    navigationSuiteItems = { /*...*/ }
) {
    // Destination content.
    when (currentDestination) {
        AppDestinations.HOME -> HomeDestination()
        AppDestinations.FAVORITES -> FavoritesDestination()
        AppDestinations.SHOPPING -> ShoppingDestination()
        AppDestinations.PROFILE -> ProfileDestination()
    }
}

色を変更

NavigationSuiteScaffold は、スキャフォールドが占有する領域全体(通常はウィンドウ全体)に Surface を作成します。さらに、スキャフォールドは、NavigationBar などの特定のナビゲーション UI を描画します。サーフェスとナビゲーションの UI はどちらも、アプリのテーマで指定された値を使用しますが、テーマの値をオーバーライドできます。

containerColor パラメータはサーフェスの色を指定します。デフォルトは、カラーパターンの背景色です。contentColor パラメータは、そのサーフェスのコンテンツの色を指定します。デフォルトは、containerColor に指定されているものの「オン」の色です。たとえば、containerColorbackground 色を使用する場合、contentColoronBackground 色を使用します。カラーシステムの仕組みについて詳しくは、Compose でのマテリアル デザイン 3 のテーマ設定をご覧ください。これらの値をオーバーライドする場合は、テーマで定義された値を使用して、アプリがダークモードとライトモードの両方をサポートするようにします。

NavigationSuiteScaffold(
    navigationSuiteItems = { /* ... */ },
    containerColor = MaterialTheme.colorScheme.primary,
    contentColor = MaterialTheme.colorScheme.onPrimary,
) {
    // Content...
}

ナビゲーション UI は NavigationSuiteScaffold サーフェスの前に描画されます。UI 色のデフォルト値は NavigationSuiteDefaults.colors() によって提供されますが、これらの値を上書きすることもできます。たとえば、ナビゲーション バーの背景を透明にして、他の値をデフォルトのままにするには、navigationBarContainerColor をオーバーライドします。

NavigationSuiteScaffold(
    navigationSuiteItems = { /* ... */ },
    navigationSuiteColors = NavigationSuiteDefaults.colors(
        navigationBarContainerColor = Color.Transparent,
    )
) {
    // Content...
}

最終的には、ナビゲーション UI の各アイテムをカスタマイズできます。item 関数を呼び出すときに、NavigationSuiteItemColors のインスタンスを渡すことができます。このクラスは、ナビゲーション バー、ナビゲーション レール、ナビゲーション ドロワー内のアイテムの色を指定します。つまり、各ナビゲーション UI タイプで同じ色を使用することも、ニーズに応じて色を変えることもできます。すべてのアイテムに同じオブジェクト インスタンスを使用するように、NavigationSuiteScaffold レベルで色を定義し、NavigationSuiteDefaults.itemColors() 関数を呼び出して、変更する色のみをオーバーライドします。

val myNavigationSuiteItemColors = NavigationSuiteDefaults.itemColors(
    navigationBarItemColors = NavigationBarItemDefaults.colors(
        indicatorColor = MaterialTheme.colorScheme.primaryContainer,
        selectedIconColor = MaterialTheme.colorScheme.onPrimaryContainer
    ),
)

NavigationSuiteScaffold(
    navigationSuiteItems = {
        AppDestinations.entries.forEach {
            item(
                icon = {
                    Icon(
                        it.icon,
                        contentDescription = stringResource(it.contentDescription)
                    )
                },
                label = { Text(stringResource(it.label)) },
                selected = it == currentDestination,
                onClick = { currentDestination = it },
                colors = myNavigationSuiteItemColors,
            )
        }
    },
) {
    // Content...
}

ナビゲーション タイプをカスタマイズする

NavigationSuiteScaffold のデフォルトの動作では、ウィンドウ サイズ クラスに基づいてナビゲーション UI が変更されます。ただし、この動作をオーバーライドすることが必要な場合もあります。たとえば、アプリがフィードのコンテンツを 1 つの大きなペインに表示する場合、アプリは拡大したウィンドウに永続的なナビゲーション ドロワーを使用できますが、コンパクト ウィンドウと中程度のウィンドウ サイズクラスではデフォルトの動作にフォールバックできます。

val adaptiveInfo = currentWindowAdaptiveInfo()
val customNavSuiteType = with(adaptiveInfo) {
    if (windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.EXPANDED) {
        NavigationSuiteType.NavigationDrawer
    } else {
        NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(adaptiveInfo)
    }
}

NavigationSuiteScaffold(
    navigationSuiteItems = { /* ... */ },
    layoutType = customNavSuiteType,
) {
    // Content...
}

参考情報