ToolbarTitleMenu
是 SwiftUI 提供的一个视图修饰符,用于在导航标题上添加下拉菜单。点击标题时会显示一个包含各种选项的菜单。
1. 基本用法 #
NavigationStack {
List {
Text("内容")
}
.navigationTitle("主页")
.toolbarTitleMenu {
Button("选项 1") {
print("选项 1 被点击")
}
Button("选项 2") {
print("选项 2 被点击")
}
Button("选项 3") {
print("选项 3 被点击")
}
}
}
2. 实用示例 #
示例 1:文档版本切换 #
struct DocumentView: View {
@State private var currentVersion = "1.0"
var body: some View {
NavigationStack {
List {
Text("文档内容")
}
.navigationTitle("文档 v\(currentVersion)")
.toolbarTitleMenu {
Button("版本 1.0") {
currentVersion = "1.0"
}
Button("版本 2.0") {
currentVersion = "2.0"
}
Button("版本 3.0") {
currentVersion = "3.0"
}
Divider()
Button("查看历史版本") {
// 显示历史版本列表
}
}
}
}
}
示例 2:带图标和分组的菜单 #
struct ContentView: View {
@State private var selectedFilter = "全部"
var body: some View {
NavigationStack {
List {
Text("内容列表")
}
.navigationTitle("筛选: \(selectedFilter)")
.toolbarTitleMenu {
Group {
Text("选择筛选条件")
.font(.caption)
.foregroundColor(.gray)
Divider()
}
Button {
selectedFilter = "全部"
} label: {
Label("全部", systemImage: "list.bullet")
}
Button {
selectedFilter = "收藏"
} label: {
Label("收藏", systemImage: "star.fill")
}
Button {
selectedFilter = "未读"
} label: {
Label("未读", systemImage: "circle.fill")
}
}
}
}
}
示例 3:结合异步操作 #
struct ProjectView: View {
@State private var currentProject = "项目 A"
@State private var isLoading = false
var body: some View {
NavigationStack {
List {
Text("项目内容")
}
.navigationTitle(currentProject)
.toolbarTitleMenu {
// 项目选择
ForEach(["项目 A", "项目 B", "项目 C"], id: \.self) { project in
Button {
switchProject(to: project)
} label: {
HStack {
Text(project)
if project == currentProject {
Image(systemName: "checkmark")
}
}
}
}
Divider()
// 项目管理选项
Button {
// 创建新项目
} label: {
Label("新建项目", systemImage: "plus")
}
Button(role: .destructive) {
// 删除当前项目
} label: {
Label("删除项目", systemImage: "trash")
}
}
.overlay(Group {
if isLoading {
ProgressView()
}
})
}
}
func switchProject(to project: String) {
isLoading = true
// 模拟异步加载
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
currentProject = project
isLoading = false
}
}
}
示例 4:多级菜单 #
struct FileView: View {
@State private var currentFile = "文档.txt"
var body: some View {
NavigationStack {
List {
Text("文件内容")
}
.navigationTitle(currentFile)
.toolbarTitleMenu {
Menu("最近文件") {
Button("文档1.txt") {
currentFile = "文档1.txt"
}
Button("文档2.txt") {
currentFile = "文档2.txt"
}
}
Menu("收藏夹") {
Button("重要文档.txt") {
currentFile = "重要文档.txt"
}
Button("笔记.txt") {
currentFile = "笔记.txt"
}
}
Divider()
Button("打开文件...") {
// 显示文件选择器
}
}
}
}
}
示例 5:状态切换和确认对话框 #
struct TaskView: View {
@State private var currentStatus = "进行中"
@State private var showConfirmation = false
@State private var pendingStatus: String?
var body: some View {
NavigationStack {
List {
Text("任务详情")
}
.navigationTitle("状态: \(currentStatus)")
.toolbarTitleMenu {
ForEach(["待处理", "进行中", "已完成", "已取消"], id: \.self) { status in
Button {
pendingStatus = status
if status == "已取消" {
showConfirmation = true
} else {
currentStatus = status
}
} label: {
Label(
status,
systemImage: status == currentStatus ? "checkmark.circle.fill" : "circle"
)
}
}
}
.alert("确认取消", isPresented: $showConfirmation) {
Button("确定", role: .destructive) {
if let status = pendingStatus {
currentStatus = status
}
}
Button("取消", role: .cancel) { }
} message: {
Text("确定要取消这个任务吗?")
}
}
}
}
3. 使用提示 #
菜单内容组织
- 使用
Divider()
分隔不同类型的选项 - 使用
Group
组织相关选项 - 可以添加图标增加可视性
- 使用
交互反馈
- 可以显示当前选中状态
- 可以添加加载状态
- 可以使用确认对话框
最佳实践
- 保持菜单项数量适中
- 确保选项描述清晰
- 考虑添加快捷键支持(如果适用)
- 对危险操作添加确认步骤
注意事项
- 需要在 NavigationStack/NavigationView 中使用
- 菜单项不宜过多
- 考虑操作的可撤销性
通过这些示例,你可以看到 ToolbarTitleMenu
非常适合用于:
- 切换视图状态
- 过滤内容
- 版本选择
- 快速操作
- 分层导航
选择合适的使用场景,可以让你的应用更加易用和高效。