构建自适应导航

大多数应用都有多个顶级目的地,可通过 应用的主要导航界面。在较小的窗口中,例如标准手机 目的地通常显示在 窗口底部在展开的窗口(例如设备上的全屏应用)中, 通常来说,与应用相邻的侧边导航栏通常是更好的选择 在按住屏幕的左右两侧时,更易于使用导航控件 设备的实际情况

NavigationSuiteScaffold 简化了切换流程 通过显示适当的导航界面可组合项,在导航界面之间实现无缝切换。 来自WindowSizeClass。其中包括 在运行时窗口大小发生变化时更改界面。默认情况下 显示以下任一界面组件:

  • 导航栏:如果宽度或高度比较紧凑,或者设备在 桌面折叠状态
  • 所有其他内容的侧边导航栏
图 1.NavigationSuiteScaffold 在紧凑窗口中显示导航栏。
<ph type="x-smartling-placeholder">
</ph>
图 2.NavigationSuiteScaffold 在展开的窗口中显示侧边导航栏。

添加依赖项

NavigationSuiteScaffoldMaterial3 自适应导航套件 库。在应用的 build.gradle 文件中为该库添加依赖项 或模块:

Kotlin


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

Groovy


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

创建 Scaffold

NavigationSuiteScaffold 的两个主要部分是导航套件项 以及所选目标页面的内容。您可以直接定义 可组合项中的导航套件项,但定义这些项的情况很常见 在其他位置(例如在枚举中):

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 函数 定义单个目的地的导航界面。目标界面是 用于导航栏、侧边栏和抽屉式导航栏中。要创建导航项,您需要 循环遍历您的 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.
}

在目的地内容 lambda 中,使用 currentDestination 值执行以下操作 决定要显示的界面如果您在应用中使用导航库,请使用该库 显示相应的目标位置。when 语句便足以满足需求:

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

更改颜色

NavigationSuiteScaffold 会在整个区域上创建一个 Surface Scaffold 所占空间,通常是整个窗口。最重要的是,基架 用于绘制特定导航界面,例如 NavigationBar。 Surface 和导航界面都使用在应用的 主题,但您可以替换主题值。

containerColor 参数用于指定 Surface 的颜色。默认 是配色方案的背景颜色。contentColor 参数 用于指定该 surface 上内容的颜色。默认值为“启用”颜色 任何为 containerColor 指定的值。例如,如果 containerColor 使用 background 颜色,contentColor 则使用 onBackground 颜色。 请参阅 Compose 中的 Material Design 3 主题设置 了解有关颜色系统工作原理的更多详情。替换这些值时 使用主题中定义的值,以便应用支持深色显示和浅色显示 模式:

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

导航界面在 NavigationSuiteScaffold Surface 前面绘制。 界面颜色的默认值由 NavigationSuiteDefaults.colors(),但你 也可以覆盖这些值例如,如果您希望 导航栏是透明的,其他值则设为默认值 替换 navigationBarContainerColor

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

最终,您可以自定义导航界面中的每项内容。在调用 item 函数,您可以传入 NavigationSuiteItemColors。该类指定了 导航栏、侧边导航栏和导航栏中的项的颜色 抽屉式导航栏。也就是说,每种导航界面类型都可以采用相同的颜色, 也可以根据需要更改颜色定义 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 的默认行为会更改导航界面 基于窗口大小 类。不过,您 您可能需要覆盖此行为例如,如果您的应用显示了一个 显示大尺寸内容窗格,则应用可以使用永久性导航 但对于展开后的窗口,则仍然会采用默认行为 较小和中等窗口大小类别:

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

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

其他资源

请参阅 Material Design 指南:

请参阅以下 androidx.compose.material3 库组件: