抽屉式导航栏

抽屉式导航栏组件是一种滑入式菜单,可让用户导航到应用的各个部分。用户可以通过从侧边滑动或点按菜单图标来激活它。

请考虑以下三种实现抽屉式导航栏的用例:

  • 内容整理:让用户能够在不同类别之间切换,例如在新闻或博客应用中。
  • 账号管理:在支持用户账号的应用中提供指向账号设置和个人资料部分的快捷链接。
  • 功能发现:在单个菜单中整理多个功能和设置,以便用户在复杂的应用中轻松发现和访问。

在 Material Design 中,抽屉式导航栏有两种类型:

  • 标准:与其他内容共享屏幕空间。
  • 模态:显示在屏幕内其他内容之上。

示例

您可以使用 ModalNavigationDrawer 可组合项实现抽屉式导航栏。

使用 drawerContent 槽提供 ModalDrawerSheet 并提供抽屉式导航栏的内容,如以下示例所示:

ModalNavigationDrawer(
    drawerContent = {
        ModalDrawerSheet {
            Text("Drawer title", modifier = Modifier.padding(16.dp))
            HorizontalDivider()
            NavigationDrawerItem(
                label = { Text(text = "Drawer Item") },
                selected = false,
                onClick = { /*TODO*/ }
            )
            // ...other drawer items
        }
    }
) {
    // Screen content
}

ModalNavigationDrawer 接受一些额外的抽屉式导航栏参数。例如,您可以使用 gesturesEnabled 参数来切换抽屉式导航栏是否响应拖动,如以下示例所示:

ModalNavigationDrawer(
    drawerContent = {
        ModalDrawerSheet {
            // Drawer contents
        }
    },
    gesturesEnabled = false
) {
    // Screen content
}

控制行为

如需控制抽屉的打开和关闭方式,请使用 DrawerState。您应使用 drawerState 参数将 DrawerState 传递给 ModalNavigationDrawer

DrawerState 可提供对 openclose 函数的访问权限,以及对与当前抽屉式导航栏状态相关的属性的访问权限。这些挂起函数需要 CoroutineScope,您可以使用 rememberCoroutineScope 实例化 CoroutineScope。您还可以调用挂起函数来响应界面事件。

val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
val scope = rememberCoroutineScope()
ModalNavigationDrawer(
    drawerState = drawerState,
    drawerContent = {
        ModalDrawerSheet { /* Drawer content */ }
    },
) {
    Scaffold(
        floatingActionButton = {
            ExtendedFloatingActionButton(
                text = { Text("Show drawer") },
                icon = { Icon(Icons.Filled.Add, contentDescription = "") },
                onClick = {
                    scope.launch {
                        drawerState.apply {
                            if (isClosed) open() else close()
                        }
                    }
                }
            )
        }
    ) { contentPadding ->
        // Screen content
    }
}

在抽屉式导航栏中创建组

以下代码段展示了如何创建包含部分和分隔符的详细抽屉式导航栏:

@Composable
fun DetailedDrawerExample(
    content: @Composable (PaddingValues) -> Unit
) {
    val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
    val scope = rememberCoroutineScope()

    ModalNavigationDrawer(
        drawerContent = {
            ModalDrawerSheet {
                Column(
                    modifier = Modifier.padding(horizontal = 16.dp)
                        .verticalScroll(rememberScrollState())
                ) {
                    Spacer(Modifier.height(12.dp))
                    Text("Drawer Title", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.titleLarge)
                    HorizontalDivider()

                    Text("Section 1", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.titleMedium)
                    NavigationDrawerItem(
                        label = { Text("Item 1") },
                        selected = false,
                        onClick = { /* Handle click */ }
                    )
                    NavigationDrawerItem(
                        label = { Text("Item 2") },
                        selected = false,
                        onClick = { /* Handle click */ }
                    )

                    HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp))

                    Text("Section 2", modifier = Modifier.padding(16.dp), style = MaterialTheme.typography.titleMedium)
                    NavigationDrawerItem(
                        label = { Text("Settings") },
                        selected = false,
                        icon = { Icon(Icons.Outlined.Settings, contentDescription = null) },
                        badge = { Text("20") }, // Placeholder
                        onClick = { /* Handle click */ }
                    )
                    NavigationDrawerItem(
                        label = { Text("Help and feedback") },
                        selected = false,
                        icon = { Icon(Icons.AutoMirrored.Outlined.Help, contentDescription = null) },
                        onClick = { /* Handle click */ },
                    )
                    Spacer(Modifier.height(12.dp))
                }
            }
        },
        drawerState = drawerState
    ) {
        Scaffold(
            topBar = {
                TopAppBar(
                    title = { Text("Navigation Drawer Example") },
                    navigationIcon = {
                        IconButton(onClick = {
                            scope.launch {
                                if (drawerState.isClosed) {
                                    drawerState.open()
                                } else {
                                    drawerState.close()
                                }
                            }
                        }) {
                            Icon(Icons.Default.Menu, contentDescription = "Menu")
                        }
                    }
                )
            }
        ) { innerPadding ->
            content(innerPadding)
        }
    }
}

代码要点

  • 使用包含部分、分隔符和导航项的 Column 填充 drawerContent
  • ModalDrawerSheet 为抽屉式导航栏提供 Material Design 样式。
  • HorizontalDivider 用于分隔抽屉中的各个部分。
  • ModalNavigationDrawer 用于创建抽屉式导航栏。
  • drawerContent 用于定义抽屉式导航栏的内容。
  • ModalDrawerSheet 中,Column 会垂直排列抽屉元素。
  • NavigationDrawerItem 可组合项代表抽屉中的各个项。
  • Scaffold 提供了界面的基本结构,包括 TopAppBar
  • TopAppBar 中的 navigationIcon 用于控制抽屉的打开和关闭状态。

结果

下图显示了抽屉打开后的显示效果,其中显示了部分和项:

一个详细的抽屉式导航栏,包含两个部分,每个部分包含多个带标签的项和图标。
图 2. 打开的抽屉式导航栏,其中包含两个嵌套的组。

其他资源