外观
DropdownMenu — 下拉菜单
锚在触发点上的浮层菜单,自带一套「文字贴左、选中右侧打勾」的项。
基本用法
kotlin
var expanded by remember { mutableStateOf(false) }
Box {
IconButton(onClick = { expanded = true }) {
Icon(Phosphor.DotsThreeVertical, contentDescription = "更多")
}
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
modifier = Modifier.width(DropdownMenuWidth), // ★ 一定给宽度
) {
DropdownMenuItem(text = "刷新", onClick = { refresh(); expanded = false })
DropdownMenuItem(text = "设置", onClick = { openSettings(); expanded = false })
}
}带前置图标、选中态、危险项:
kotlin
DropdownMenu(expanded, onDismissRequest, Modifier.width(DropdownMenuWidth)) {
DropdownMenuItem(
text = "跟随系统",
selected = mode == Mode.System,
leadingIcon = Phosphor.CircleHalf,
onClick = { mode = Mode.System },
)
DropdownMenuItem(
text = "删除",
contentColor = MaterialTheme.colorScheme.error,
onClick = { delete() },
)
}参数
DropdownMenu
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
expanded | Boolean | — | 是否展开,状态自己托管 |
onDismissRequest | () -> Unit | — | 点到外面 / 返回键时的回调,必须把 expanded 置回 false |
modifier | Modifier | Modifier | 修饰符。宽度建议给 Modifier.width(DropdownMenuWidth) |
offset | DpOffset | DpOffset.Zero | 相对锚点的偏移 |
colors | DropdownMenuColors | DropdownMenuDefaults.colors() | 容器配色 |
content | @Composable ColumnScope.() -> Unit | — | 菜单内容,通常放 DropdownMenuItem |
DropdownMenuItem
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
text | String | — | 菜单项文字,单行、超长省略 |
onClick | () -> Unit | — | 点击回调。不会自动关闭菜单 |
selected | Boolean | false | 选中时右侧出对勾,文字从 bodyLarge 升到 titleMedium |
leadingIcon | ImageVector? | null | 前置图标(20dp)。只有真的传了才占位 |
contentColor | Color? | null | 文字与前置图标颜色;null 取 colors.contentColor |
selectedIconTint | Color? | null | 对勾颜色;null 取 colors.selectedIconTint |
colors | DropdownMenuItemColors | DropdownMenuItemDefaults.colors() | 配色 |
配色类
| 类 | 字段 | 默认值 |
|---|---|---|
DropdownMenuColors | containerColor | MaterialTheme.colorScheme.surfaceContainer |
DropdownMenuItemColors | contentColor | MaterialTheme.colorScheme.onSurface |
selectedIconTint | MaterialTheme.colorScheme.onSurface |
DropdownMenuWidth
kotlin
val DropdownMenuWidth = 180.dp要点
- 一定要给宽度。 不给的话
DropdownMenu按内容自适应:「设置」「个人中心」这种两三个字的中文会缩成窄窄一条,看着像控件没渲染完整,而且各菜单宽度不一、右对齐后左边缘参差。全站统一Modifier.width(DropdownMenuWidth)。 DropdownMenuItem点了不会自己关菜单。 每个onClick里都要自己expanded = false,漏一个就会出现「点了菜单还杵在那儿」。leadingIcon是「有才占位」。 不传时文字直接贴左,不会留一段空缩进。所以同一份菜单里可以一项带图标、一项不带 —— 只是左边缘会不齐,视觉上自己接受。- 选中态字号不变,只加字重。
bodyLarge和titleMedium都是 16sp,只差 Normal → Medium。这是刻意的:改用titleSmall(14sp)会让选中项看起来像换了一种字体,而不只是「重了一点」。 - 危险项用
contentColor = MaterialTheme.colorScheme.error,不要新建一套红色配色,也不要在页面里手写色值。
说明
- 为什么同时用「表面色阶」和「投影」:这不是重复。
surfaceContainer比页面背景亮一档,深色主题下投影几乎看不见,靠它分层;shadowElevation = 6.dp让浮层在白底上真的浮起来,浅色主题下靠它分层。两种机制各管一个主题,缺一个就会在另一个主题下失效 —— 这里曾经把shadowElevation设成 0,理由是「表面音阶比投影可靠」,代价是浅色下菜单变成白底上一块平的灰方块。 - 形状取
AppShapes.cardSmall(16dp):比卡片小一档,浮层不需要那么软的边。 - 全站的下拉菜单项只有这一种排法。 曾经首页的 ⋮ 菜单和设置页的主题模式下拉各写一遍,于是同一类浮层出现了两种观感:一边文字右边打勾、加粗;一边是左边打勾、还因为「给前置图标留 20dp 占位」而整体被顶出一截 —— 在纯文字菜单里,那个占位就是一段莫名其妙的缩进。