菜单 (Menus)
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,
)
}
}
}
}