Skip to content

菜单 (Menus)

源:Material Design 菜单

1. 下拉菜单 (DropdownMenu)

通常由一个图标按钮触发。

kotlin
var expanded by remember { mutableStateOf(false) }

Box {
    IconButton(onClick = { expanded = true }) {
        Icon(Icons.Default.MoreVert, contentDescription = "更多")
    }

    DropdownMenu(
        expanded = expanded,
        onDismissRequest = { expanded = false }
    ) {
        DropdownMenuItem(
            text = { Text("刷新") },
            onClick = { 
                /* 刷新逻辑 */
                expanded = false 
            },
            leadingIcon = { Icon(Icons.Default.Refresh, null) }
        )
        DropdownMenuItem(
            text = { Text("设置") },
            onClick = { expanded = false },
            leadingIcon = { Icon(Icons.Default.Settings, null) }
        )
    }
}

定位

DropdownMenu 默认会尝试锚定在其父布局 (Box) 的位置。务必将触发按钮和菜单包裹在同一个 Box 中。

2. 暴露下拉菜单 (ExposedDropdownMenu)

这是 Material Design 中替代传统 Spinner 的组件,看起来像一个带下拉列表的 TextField。

kotlin
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ExposedDropdownMenuSample() {
    val options = listOf("选项 A", "选项 B", "选项 C")
    var expanded by remember { mutableStateOf(false) }
    var selectedOptionText by remember { mutableStateOf(options[0]) }

    ExposedDropdownMenuBox(
        expanded = expanded,
        onExpandedChange = { expanded = !expanded },
    ) {
        TextField(
            // 必须:告诉 Box 文本框的坐标,以便菜单正确锚定
            modifier = Modifier.menuAnchor(), 
            readOnly = true, // 禁止手动输入,只能选
            value = selectedOptionText,
            onValueChange = {},
            label = { Text("请选择") },
            trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
            colors = ExposedDropdownMenuDefaults.textFieldColors(),
        )
        
        ExposedDropdownMenu(
            expanded = expanded,
            onDismissRequest = { expanded = false },
        ) {
            options.forEach { selectionOption ->
                DropdownMenuItem(
                    text = { Text(selectionOption) },
                    onClick = {
                        selectedOptionText = selectionOption
                        expanded = false
                    },
                    contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
                )
            }
        }
    }
}