Menu
概述
SwiftUI菜单提供了一种直观的方式,让用户能够选择操作,访问次级界面,或者查看额外的选项。菜单可以包含一系列菜单项,每个菜单项可以是一个按钮、切换开关、复选框,或者其他SwiftUI控件。
菜单非常适合用于导航、设置和应用程序级操作,特别是在移动设备上,这些设备空间有限。
基本菜单创建
使用 String 创建菜单
1import SwiftUI
2struct ContentView: View {
3 var body: some View {
4 Menu("菜单") {
5 // 菜单内容
6 }
7 }
8}
使用 Label 创建菜单
1Menu {
2 // 菜单内容
3} label: {
4 Label("菜单", systemImage: "menu")
5}
6
7Menu("菜单", systemImage: "doc.text") {
8 // 菜单内容
9}
菜单内容类型
Tip除了用
Button作为 Menu 的内容外, 还可以用Toggle、Divider、Label、Text、Section、Picker、Stepper等控件。
按钮菜单
1Menu("菜单") {
2 // 普通按钮
3 Button("操作1") { ... }
4 // 带图标的按钮
5 Button("偏好设置", systemImage: "gearshape") { ... }
6 // 角色按钮
7 Button("Delete…", systemImage: "trash", role: .destructive) { ... }
8}
切换菜单
1@State private var isDarkMode = false
2@State private var isOpen = false
3
4Menu("外观") {
5 // 默认
6 Toggle("深色模式", isOn: $isDarkMode)
7 // 自定义
8 Toggle(isOn: $isOpen) {
9 Label("开关", systemImage: "suit.heart")
10 Text("标题、图标、子标题")
11 }
12}
单选菜单
1@State private var selectedOption = "选项1"
2let options = ["选项1", "选项2", "选项3"]
3
4Menu("单选选项") {
5 ForEach(options, id: \.self) { option in
6 Button {
7 selectedOption = option
8 } label: {
9 Label(option, systemImage: selectedOption == option ? "checkmark.circle.fill" : "circle")
10 }
11 }
12}
复选菜单
1@State private var selectedOptions = ["选项1", "选项3"]
2let options = ["选项1", "选项2", "选项3"]
3
4Menu("复选选项") {
5 ForEach(options, id: \.self) { option in
6 Button {
7 if selectedOptions.contains(option) {
8 selectedOptions.removeAll { $0 == option }
9 } else {
10 selectedOptions.append(option)
11 }
12 } label: {
13 Label(option, systemImage: selectedOptions.contains(option) ? "checkmark.circle.fill" : "circle")
14 }
15 }
16}
带标签的菜单
1Menu("工具") {
2 Button("打开") {
3 // 打开记事本
4 }
5 Button("新建") {
6 // 新建记事本
7 }
8 Label("记事本", systemImage: "doc.text")
9}
自适应控制菜单
条件性菜单项
1struct ContentView: View {
2 @State private var isLoggedIn = false
3 @State private var userRole: UserRole = .guest
4
5 var body: some View {
6 Menu("账户") {
7 if isLoggedIn {
8 Button("个人资料") {
9 // 打开个人资料
10 }
11
12 Button("设置") {
13 // 打开设置
14 }
15
16 Button("登出", action: {
17 isLoggedIn = false
18 })
19
20 Divider()
21
22 Text("已登录")
23 .foregroundColor(.secondary)
24 } else {
25 Button("登录") {
26 isLoggedIn = true
27 }
28
29 Button("注册") {
30 // 打开注册
31 }
32 }
33
34 if userRole == .admin {
35 Divider()
36 Button("管理") {
37 // 打开管理面板
38 }
39 }
40 }
41 }
42}
使用标签来组织菜单项
分组菜单项
1Menu("格式") {
2 Text("字体")
3 .font(.headline)
4 .foregroundColor(.secondary)
5
6 Button("标题1") {
7 // 设置字体大小
8 }
9
10 Button("标题2") {
11 // 设置字体大小
12 }
13
14 Divider()
15
16 Text("对齐")
17 .font(.headline)
18 .foregroundColor(.secondary)
19
20 Button("左对齐") {
21 // 左对齐
22 }
23
24 Button("居中") {
25 // 居中
26 }
27
28 Button("右对齐") {
29 // 右对齐
30 }
31}
高级菜单功能
菜单状态控制
1struct ContentView: View {
2 @State private var isMenuOpen = false
3
4 var body: some View {
5 Menu("操作", isOpen: $isMenuOpen) {
6 Button("操作1", action: {
7 // 执行操作
8 })
9
10 Button("操作2", action: {
11 // 执行操作
12 })
13 }
14
15 Button("打开菜单") {
16 isMenuOpen = true
17 }
18 }
19}
菜单内容绑定
1struct ContentView: View {
2 @State private var menuItems: [MenuItem] = [
3 MenuItem(title: "新建", icon: "doc.badge.plus", action: createNew),
4 MenuItem(title: "打开", icon: "folder", action: openFile),
5 MenuItem(title: "保存", icon: "square.and.arrow.down", action: saveFile),
6 ]
7
8 var body: some View {
9 Menu("文件") {
10 ForEach(menuItems, id: \.self) { item in
11 Button(action: item.action) {
12 Label(item.title, systemImage: item.icon)
13 }
14 }
15 }
16 }
17}
18
19struct MenuItem: Identifiable {
20 let id = UUID()
21 let title: String
22 let icon: String
23 let action: () -> Void
24}
响应式菜单
根据数据动态生成菜单项
1struct ContentView: View {
2 @State private var availableFeatures: [Feature] = [
3 Feature(title: "翻译", icon: "globe", isAvailable: true),
4 Feature(title: "语音输入", icon: "mic", isAvailable: false),
5 Feature(title: "屏幕录制", icon: "screen.recording", isAvailable: true),
6 ]
7
8 var body: some View {
9 Menu("功能") {
10 ForEach(availableFeatures) { feature in
11 if feature.isAvailable {
12 Button(action: {
13 // 使用该功能
14 }) {
15 Label(feature.title, systemImage: feature.icon)
16 }
17 } else {
18 Label(feature.title, systemImage: feature.icon)
19 .foregroundColor(.secondary)
20 }
21 }
22 }
23 }
24}
25
26struct Feature {
27 let title: String
28 let icon: String
29 let isAvailable: Bool
30}
最佳实践
1. 菜单项的组织
- 使用文本和图标来为菜单项创建一个清晰的标签
- 使用分隔线来分隔不同的菜单组
- 将相关的菜单项放在一起
2. 条件性菜单项
- 根据应用状态(如用户登录状态)显示或隐藏菜单项
- 使用设备特征(如尺寸类)来调整菜单项
- 动态生成菜单项以适应不同的数据集
3. 无障碍访问
- 为菜单项提供描述性的标签
- 使用合适的系统图标来表示菜单项的功能
- 确保菜单项的内容可读性和足够的点击区域
4. 菜单性能
- 避免在菜单内部创建复杂的视图层次
- 对于动态生成的菜单项,考虑使用
ForEach而不是硬编码 - 限制菜单项的数量,以避免布局问题
完整示例:设置菜单
1import SwiftUI
2
3struct SettingsView: View {
4 @AppStorage("notificationEnabled") private var notificationEnabled = true
5 @AppStorage("darkMode") private var darkMode = false
6 @AppStorage("language") private var language = Locale.current.identifier
7 @State private var showAbout = false
8
9 var body: some View {
10 NavigationView {
11 List {
12 Section("通知") {
13 Toggle("启用通知", isOn: $notificationEnabled)
14 }
15
16 Section("外观") {
17 Toggle("深色模式", isOn: $darkMode)
18 }
19
20 Section("语言") {
21 Menu("语言") {
22 ForEach(Array(Locale.autoupdating.currentIdentifiers), id: \.self) { locale in
23 Button(locale.capitalized) {
24 language = locale
25 }
26 }
27 }
28 }
29
30 Section("关于") {
31 Button("关于应用", action: {
32 showAbout = true
33 })
34 }
35 }
36 .navigationTitle("设置")
37 }
38 .sheet(isPresented: $showAbout) {
39 AboutView()
40 }
41 }
42}
43
44struct AboutView: View {
45 @Environment(\,.dismiss) var dismiss
46
47 var body: some View {
48 NavigationView {
49 VStack {
50 Image(systemName: "app")
51 .font(.largeTitle)
52 .padding()
53
54 Text("我的应用")
55 .font(.title)
56
57 Text("版本 1.0.0")
58 .foregroundColor(.secondary)
59
60 Spacer()
61 }
62 .navigationTitle("关于")
63 .navigationBarTitleDisplayMode(.inline)
64 .toolbar {
65 ToolbarItem(placement: .navigationBarTrailing) {
66 Button("完成", action: {
67 dismiss()
68 })
69 }
70 }
71 }
72 }
73}
总结
菜单是SwiftUI中一个强大的UI组件,可以让用户访问和执行各种操作。通过使用标签、图标、分隔线和条件性菜单项,您可以创建出丰富且用户友好的菜单体验。记住保持菜单的简洁性,并根据应用状态和设备特征来动态生成菜单项。
菜单是构建现代化iOS应用的基石之一。