Apple 如何在以 SF Symbol 表示当前值的菜单中显示选中状态?
数据小许
结论
可以先采用 Menu 内嵌 Picker 的实现:菜单入口显示当前选项的 SF Symbol,菜单内用 Label 显示选项文字和图标,单选状态和系统 checkmark 由 Picker 管理,无需手动添加第二个 Image。
Apple 的官方示例展示了菜单内的 Picker,也有用 Label 为选项添加图标的代码。这可以作为实现参考,但不能据此认定 Apple 自家应用使用了相同代码。Apple 官方菜单示例
为什么不必手动放置 checkmark
选项图标表示选项的含义,checkmark 表示选择状态。使用 Picker(selection:) 后,系统会根据绑定值标记当前选项,不必把 checkmark 作为另一个图像放进菜单项的 label。
原问题中“每行只能显示一个图像”的观察,不足以说明菜单无法同时显示选项图标和选中标记。可以先用控件表达选择关系,再由系统呈现状态。
实现示例
以下示例包含两种显示方式。菜单入口只显示当前选项的图标,展开后显示各选项的文字和图标:
import SwiftUI
struct DisplayModeMenu: View {
enum DisplayMode: String, CaseIterable, Hashable {
case list = "列表"
case grid = "网格"
var systemImage: String {
switch self {
case .list:
return "list.bullet"
case .grid:
return "square.grid.2x2"
}
}
}
@State private var selected: DisplayMode = .list
var body: some View {
Menu {
Picker("显示方式", selection: $selected) {
ForEach(DisplayMode.allCases, id: \.self) { mode in
Label(mode.rawValue, systemImage: mode.systemImage)
.tag(mode)
}
}
.pickerStyle(.inline)
} label: {
Label(
"显示方式:\(selected.rawValue)",
systemImage: selected.systemImage
)
.labelStyle(.iconOnly)
}
}
}
代码中:
selection和.tag(mode)使用相同类型,让Picker识别当前选项。.pickerStyle(.inline)让选项直接出现在外层菜单中。对菜单内部的Picker使用.menu会形成子菜单。Apple 的 menu 样式说明.labelStyle(.iconOnly)只应用于菜单入口,保留入口的文字语义;菜单内的选项仍使用各自的Label。
图标位置与 Apple 应用实例
上述代码定义了选项的图标、文字和选择状态,但不能保证图标始终位于文字左侧。原生菜单的具体排列受平台、系统版本和上下文影响,应在目标 iOS 版本上确认显示效果。如果必须固定每个元素的位置,再考虑自定义弹出界面。
现有材料没有可核对的 Apple 应用截图或具体界面,因此无法可靠列举完全对应的自家应用实例。官方文档可以确认,在菜单中使用带图标的 Picker 选项是受支持的用法;实际产品的内部实现不能仅凭外观判断。
备注:内容仅供参考。
