跳转到内容

WindowDropdownMenu

WindowDropdownMenu 是基于 BasicComponent 的封装,点击后会展开 WindowDropdownPopup(通过 Dialog 在窗口级别渲染)。与 WindowDropdownPreference 不同,它不再持有单一的选中索引——选中状态完全保存在每个 DropdownItemselectedonClick 上。适用于动作菜单、多选菜单,或弹出项之间不构成单选互斥关系的场景。

引入

kotlin
import io.github.suqi8.coui.kmp.menu.WindowDropdownMenu
import io.github.suqi8.coui.kmp.basic.DropdownEntry
import io.github.suqi8.coui.kmp.basic.DropdownItem

基本用法

传入单个 DropdownEntry 即可显示一个基础下拉菜单行,无需 Scaffold

kotlin
var selectedIndex by remember { mutableStateOf(0) }
val entry = DropdownEntry(
    items = listOf("选项 1", "选项 2", "选项 3").mapIndexed { index, text ->
        DropdownItem(
            text = text,
            selected = selectedIndex == index,
            onClick = { selectedIndex = index },
        )
    }
)

WindowDropdownMenu(
    title = "下拉菜单",
    entry = entry
)

分组菜单

传入 List<DropdownEntry> 即可显示由分割线隔开的多个分组。collapseOnSelection 默认为 entries.size <= 1,多分组场景下选中后弹出框保持打开以便连续选择。

kotlin
var sizeIndex by remember { mutableStateOf(0) }
var colorIndex by remember { mutableStateOf(0) }
val entries = listOf(
    DropdownEntry(
        items = listOf("小", "中").mapIndexed { index, text ->
            DropdownItem(text = text, selected = sizeIndex == index, onClick = { sizeIndex = index })
        }
    ),
    DropdownEntry(
        items = listOf("红色", "绿色", "蓝色").mapIndexed { index, text ->
            DropdownItem(text = text, selected = colorIndex == index, onClick = { colorIndex = index })
        }
    )
)

WindowDropdownMenu(
    title = "分组菜单",
    entries = entries,
    collapseOnSelection = false
)

多选

选中状态保存在 DropdownItem.selected 上,可以同时选中多个条目,在每个条目的 onClick 中切换选中状态即可。

kotlin
var selected by remember { mutableStateOf(setOf("A1", "B2")) }
val entries = listOf(
    DropdownEntry(
        items = listOf("A1", "A2").map { text ->
            DropdownItem(
                text = text,
                selected = text in selected,
                onClick = {
                    selected = if (text in selected) selected - text else selected + text
                }
            )
        }
    ),
    DropdownEntry(
        items = listOf("B1", "B2", "B3").map { text ->
            DropdownItem(
                text = text,
                selected = text in selected,
                onClick = {
                    selected = if (text in selected) selected - text else selected + text
                }
            )
        }
    )
)

WindowDropdownMenu(
    title = "多选菜单",
    entries = entries,
    collapseOnSelection = false
)

监听展开状态

kotlin
var expanded by remember { mutableStateOf(false) }
val entry = DropdownEntry(
    items = listOf("选项 1", "选项 2", "选项 3").map { DropdownItem(text = it) }
)

WindowDropdownMenu(
    title = "监听展开",
    summary = if (expanded) "展开" else "收起",
    entry = entry,
    onExpandedChange = { expanded = it }
)

带提示槽的选项

hint 槽渲染在标题区块与选中指示图标之间,最大宽度 40dp,适合放红点、计数徽标或极短标签。与 ColorOS 一致,行被禁用时提示槽整体隐藏。

kotlin
val entry = DropdownEntry(
    items = listOf(
        DropdownItem(text = "Inbox", hint = { Badge(count = 12) }),
        DropdownItem(text = "Updates", hint = { Badge() }),
        // 该行被禁用,因此徽标不会显示。
        DropdownItem(text = "Archive", hint = { Badge(count = 3) }, enabled = false),
    )
)

Scaffold {
    WindowDropdownMenu(title = "Hints", entry = entry)
}

分组标题

DropdownEntry 可声明 title,渲染为该分组各项之上的不可点击标题行(12sp 中等字重、次级标签 色、最多 2 行)。分组标题与已有的分组分割线可以共存。

kotlin
val entries = listOf(
    DropdownEntry(
        title = "Sort by",
        items = listOf("Name", "Date modified").map { DropdownItem(text = it) }
    ),
    DropdownEntry(
        title = "Order",
        items = listOf("Ascending", "Descending").map { DropdownItem(text = it) }
    )
)

Scaffold {
    WindowDropdownMenu(title = "Group Headers", entries = entries)
}

警示项

设置 alert = true 可将某项标记为危险操作,其标题使用错误色而非常规标签色;被禁用的警示项仍回退 到禁用色。

kotlin
val entry = DropdownEntry(
    items = listOf(
        DropdownItem(text = "Rename"),
        DropdownItem(text = "Delete", alert = true),
    )
)

Scaffold {
    WindowDropdownMenu(title = "Alert Item", entry = entry)
}

组件状态

禁用状态

kotlin
WindowDropdownMenu(
    title = "禁用菜单",
    summary = "此菜单当前不可用",
    entry = DropdownEntry(items = listOf(DropdownItem(text = "选项 1"))),
    enabled = false
)

当所有 DropdownEntry 都不包含任何条目时,菜单也会被隐式禁用。

属性

WindowDropdownMenu 属性(Entries 重载)

属性名类型说明默认值是否必须
entriesList<DropdownEntry>由分割线隔开的下拉选项分组-
titleString菜单行的标题-
modifierModifier应用于组件的修饰符Modifier
titleColorBasicComponentColors标题文本的颜色配置BasicComponentDefaults.titleColor()
summaryString?菜单的摘要说明null
summaryColorBasicComponentColors摘要文本的颜色配置BasicComponentDefaults.summaryColor()
dropdownColorsDropdownColors下拉选项的颜色配置DropdownDefaults.dropdownColors()
startAction@Composable (() -> Unit)?左侧显示的自定义内容null
bottomAction(@Composable () -> Unit)?底部显示的自定义内容null
insideMarginPaddingValues组件内部内容的边距BasicComponentDefaults.InsideMargin
maxHeightDp?下拉菜单的最大高度null
enabledBoolean组件是否可交互true
collapseOnSelectionBoolean每次选中后是否关闭弹出框entries.size <= 1
onExpandedChange((Boolean) -> Unit)?展开状态变化时的回调null

Entry 重载属性

属性名类型说明默认值是否必须
entryDropdownEntry单个下拉选项分组-
collapseOnSelectionBoolean选中后是否关闭弹出框true

其余参数与上方 entries 重载完全一致。

属性名类型说明默认值是否必须
itemsList<DropdownItem>此分组中显示的条目-
enabledBoolean此分组是否启用。为 false 时禁用整组条目;为 true 时仍会遵循每个条目的 enabled 状态true
titleString?可选的不可点击分组标题,渲染在各项之上(12sp 中等字重、次级标签色、最多 2 行)null
属性名类型说明默认值是否必须
textString选项显示的文本-
enabledBoolean选项是否可点击,禁用时置灰true
selectedBoolean选项是否处于选中状态false
onClick(() -> Unit)?点击选项时触发的回调null
icon@Composable ((Modifier) -> Unit)?显示在选项文本前的图标null
summaryString?显示在选项文本下方的摘要文本null
childrenList<DropdownItem>?可选的子菜单项;仅级联变体null
hint@Composable (() -> Unit)?可选的尾部提示槽(徽标、红点、短计数),显示在选中指示图标之前,最大宽度 40dp。行被禁用时整体隐藏null
alertBoolean是否为警示(危险)项;其标题使用错误色false
属性名类型说明
contentColorColor选项标题颜色
summaryColorColor选项摘要颜色
containerColorColor选项背景颜色
selectedContentColorColor选中项标题颜色
selectedSummaryColorColor选中项摘要颜色
selectedContainerColorColor选中项背景颜色
selectedIndicatorColorColor选中指示图标颜色
disabledContentColorColor禁用项标题颜色
alertContentColorColor警示项标题颜色
headerColorColor分组标题行的标题颜色

变更日志

基于 Apache-2.0 许可发布