菜单

下拉菜单允许用户点击图标、文本字段或其他组件,然后从临时界面上的选项列表中进行选择。本指南介绍了如何创建基本菜单以及带有分隔线和图标的更复杂菜单。

A A dropdown menu with two options displayed. An icon with three vertical dots indicates that clicking it opens the menu.
图 1. 一个基本的下拉菜单,列出了两个项目。

API surface

使用 DropdownMenuDropdownMenuItemIconButton 组件来实现自定义下拉菜单。DropdownMenuDropdownMenuItem 组件用于显示菜单项,而 IconButton 则是显示或隐藏下拉菜单的触发器。

DropdownMenu 组件的关键参数包括:

  • expanded:指示菜单是否可见。
  • onDismissRequest:用于处理菜单关闭。
  • content:菜单的可组合内容,通常包含 DropdownMenuItem 可组合项。

DropdownMenuItem 的关键参数包括:

  • text:定义菜单项中显示的内容。
  • onClick:处理与菜单项互动的回调。

创建一个基本下拉菜单

以下代码段演示了一个最简单的 DropdownMenu 实现:

@Composable
fun MinimalDropdownMenu() {
    var expanded by remember { mutableStateOf(false) }
    Box(
        modifier = Modifier
            .padding(16.dp)
    ) {
        IconButton(onClick = { expanded = !expanded }) {
            Icon(Icons.Default.MoreVert, contentDescription = "More options")
        }
        DropdownMenu(
            expanded = expanded,
            onDismissRequest = { expanded = false }
        ) {
            DropdownMenuItem(
                text = { Text("Option 1") },
                onClick = { /* Do something... */ }
            )
            DropdownMenuItem(
                text = { Text("Option 2") },
                onClick = { /* Do something... */ }
            )
        }
    }
}

关于代码的要点:

  • 定义一个包含两个菜单项的基本 DropdownMenu
  • expanded 参数控制菜单的可见性,即展开或折叠。
  • onDismissRequest 参数定义了一个回调,当用户关闭菜单时执行该回调。
  • DropdownMenuItem 可组合项表示下拉菜单中的可选项目。
  • 一个 IconButton 触发菜单的展开和折叠。

结果

A dropdown menu triggered by an icon with three vertical dots. The menu displays two selectable options, Option 1 and Option 2.
图 2. 一个只有两个选项的最简单的下拉菜单。

创建更长的下拉菜单

如果所有菜单项无法一次性显示,DropdownMenu 默认是可滚动的。以下代码段创建了一个更长、可滚动的下拉菜单:

@Composable
fun LongBasicDropdownMenu() {
    var expanded by remember { mutableStateOf(false) }
    // Placeholder list of 100 strings for demonstration
    val menuItemData = List(100) { "Option ${it + 1}" }

    Box(
        modifier = Modifier
            .padding(16.dp)
    ) {
        IconButton(onClick = { expanded = !expanded }) {
            Icon(Icons.Default.MoreVert, contentDescription = "More options")
        }
        DropdownMenu(
            expanded = expanded,
            onDismissRequest = { expanded = false }
        ) {
            menuItemData.forEach { option ->
                DropdownMenuItem(
                    text = { Text(option) },
                    onClick = { /* Do something... */ }
                )
            }
        }
    }
}

关于代码的要点:

  • 当其内容的总高度超过可用空间时,DropdownMenu 是可滚动的。此代码创建了一个可滚动的 DropdownMenu,它显示 100 个占位符项目。
  • forEach 循环动态生成 DropdownMenuItem 可组合项。这些项目不是懒加载的,这意味着所有 100 个下拉项都在组合中创建并存在。
  • 点击 IconButton 时,它会触发 DropdownMenu 的展开和折叠。
  • 每个 DropdownMenuItem 中的 onClick lambda 允许您定义用户选择菜单项时执行的操作。

结果

上述代码段生成以下可滚动菜单:

A dropdown menu with many options, requiring scrolling to view all
  items.
图 3. 一个长的可滚动下拉菜单。

创建带分隔线的较长下拉菜单

以下代码段显示了下拉菜单的更高级实现。在此代码段中,菜单项添加了前导和尾随图标,并用分隔线分隔菜单项组。

@Composable
fun DropdownMenuWithDetails() {
    var expanded by remember { mutableStateOf(false) }

    Box(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp)
    ) {
        IconButton(onClick = { expanded = !expanded }) {
            Icon(Icons.Default.MoreVert, contentDescription = "More options")
        }
        DropdownMenu(
            expanded = expanded,
            onDismissRequest = { expanded = false }
        ) {
            // First section
            DropdownMenuItem(
                text = { Text("Profile") },
                leadingIcon = { Icon(Icons.Outlined.Person, contentDescription = null) },
                onClick = { /* Do something... */ }
            )
            DropdownMenuItem(
                text = { Text("Settings") },
                leadingIcon = { Icon(Icons.Outlined.Settings, contentDescription = null) },
                onClick = { /* Do something... */ }
            )

            HorizontalDivider()

            // Second section
            DropdownMenuItem(
                text = { Text("Send Feedback") },
                leadingIcon = { Icon(Icons.Outlined.Feedback, contentDescription = null) },
                trailingIcon = { Icon(Icons.AutoMirrored.Outlined.Send, contentDescription = null) },
                onClick = { /* Do something... */ }
            )

            HorizontalDivider()

            // Third section
            DropdownMenuItem(
                text = { Text("About") },
                leadingIcon = { Icon(Icons.Outlined.Info, contentDescription = null) },
                onClick = { /* Do something... */ }
            )
            DropdownMenuItem(
                text = { Text("Help") },
                leadingIcon = { Icon(Icons.AutoMirrored.Outlined.Help, contentDescription = null) },
                trailingIcon = { Icon(Icons.AutoMirrored.Outlined.OpenInNew, contentDescription = null) },
                onClick = { /* Do something... */ }
            )
        }
    }
}

此代码在 Box 中定义了一个 DropdownMenu

关于代码的要点:

  • leadingIcontrailingIcon 参数用于向 DropdownMenuItem 的开头和结尾添加图标。
  • 一个 IconButton 触发菜单的展开。
  • DropdownMenu 包含多个 DropdownMenuItem 可组合项,每个项都代表一个可选操作。
  • HorizontalDivider 可组合项插入一条水平线以分隔菜单项组。

结果

上述代码段生成一个带图标和分隔线的下拉菜单:

A dropdown menu with sections for Profile, Settings, Send Feedback, About, and
图 4. 一个分为多个部分,带有前导和尾随图标的下拉菜单。

其他资源