mcpField
T
toolbars

toolbars

github.com/rshankras设计与 UI83879 次安装14 周前更新
代码仓库

关于 toolbars

面向 SwiftUI 开发者的工具栏模式指南,介绍自定义工具栏、搜索集成、系统项目位置和过渡效果。还涵盖 iOS、iPadOS 与 macOS 的平台差异及 API 版本要求。

主要功能

  1. 01添加可自定义工具栏项目
  2. 02配置搜索栏行为与位置
  3. 03调整系统工具栏项目位置
  4. 04创建工具栏过渡效果
  5. 05参考平台差异与 API 版本

适用场景

  1. 01为应用添加用户可配置的工具栏
  2. 02将搜索栏移至合适位置
  3. 03为工具栏按钮添加缩放过渡
  4. 04检查跨平台工具栏布局

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/rshankras/claude-code-apple-skills --skill toolbars

安装后在 Claude Code 中输入/toolbars确认已加载。

详细介绍

SwiftUI 工具栏

适用于 SwiftUI 应用的现代工具栏模式。涵盖可自定义工具栏、增强的搜索集成、新的放置位置、过渡效果以及平台特定注意事项。

此技能的触发条件

当用户:

  • 想要添加或自定义工具栏时
  • 询问可自定义/用户可配置的工具栏时
  • 需要在工具栏的特定位置放置搜索字段时
  • 想要工具栏项目过渡或动画时
  • 询问工具栏放置位置(bottomBar、largeSubtitle 等)时
  • 需要了解平台特定的工具栏行为(iOS 与 macOS)时
  • 想要重新定位系统工具栏项目(搜索、侧边栏)时

决策树

What toolbar feature do you need?
|
+- User-customizable toolbar (add/remove/reorder items)
|  +- Use .toolbar(id:) with ToolbarItem(id:)
|
+- Search field in toolbar
|  +- Minimize to button -> .searchToolbarBehavior(.minimize)
|  +- Reposition search -> DefaultToolbarItem(kind: .search, placement:)
|
+- Toolbar transition/animation
|  +- Zoom transition from toolbar item -> .matchedTransitionSource(id:in:)
|  +- Hide glass background -> .sharedBackgroundVisibility(.hidden)
|
+- Custom subtitle area content
|  +- Use ToolbarItem(placement: .largeSubtitle)
|
+- System toolbar items with custom placement
|  +- DefaultToolbarItem(kind: .search/.sidebar, placement:)

API 可用性

API最低版本备注
.toolbar { }iOS 14基本工具栏
ToolbarItem(placement:)iOS 14标准放置位置
.toolbar(id:)iOS 16可自定义工具栏
ToolbarItem(id:)iOS 16可自定义工具栏中的项目
ToolbarSpaceriOS 16固定和灵活间隔器
.searchable()iOS 15搜索集成
.searchToolbarBehavior(.minimize)iOS 17最小化搜索按钮
DefaultToolbarItem(kind:placement:)iOS 18重新定位系统项目
ToolbarItem(placement: .largeSubtitle)iOS 18副标题区域内容
.matchedTransitionSource(id:in:)iOS 18工具栏过渡源
.sharedBackgroundVisibility()iOS 18控制玻璃背景

可自定义工具栏

允许用户通过添加、移除和重新排列工具栏项目来自定义工具栏:

ContentView()
    .toolbar(id: "main-toolbar") {
        ToolbarItem(id: "tag") {
            TagButton()
        }
        ToolbarItem(id: "share") {
            ShareButton()
        }
        ToolbarSpacer(.fixed)
        ToolbarItem(id: "more") {
            MoreButton()
        }
    }
工具栏间隔器
ToolbarSpacer(.fixed)      // Fixed-width space
ToolbarSpacer(.flexible)   // Flexible space — pushes items apart
反模式
// ❌ Missing IDs in customizable toolbar — items can't be customized
.toolbar(id: "main") {
    ToolbarItem {           // No id parameter
        ShareButton()
    }
}

// ✅ Every item needs its own ID
.toolbar(id: "main") {
    ToolbarItem(id: "share") {
        ShareButton()
    }
}

增强的搜索集成

最小化搜索

将搜索字段显示为紧凑按钮,轻点后展开:

@State private var searchText = ""

NavigationStack {
    RecipeList()
        .searchable(text: $searchText)
        .searchToolbarBehavior(.minimize)
}
重新定位搜索

将默认搜索字段移动到工具栏中的其他位置:

NavigationSplitView {
    AllCalendarsView()
} detail: {
    SelectedCalendarView()
        .searchable(text: $query)
        .toolbar {
            ToolbarItem(placement: .bottomBar) {
                CalendarPicker()
            }
            ToolbarItem(placement: .bottomBar) {
                Invites()
            }
            DefaultToolbarItem(kind: .search, placement: .bottomBar)
            ToolbarSpacer(placement: .bottomBar)
            ToolbarItem(placement: .bottomBar) {
                NewEventButton()
            }
        }
}

系统定义的工具栏项目

使用自定义放置位置重新定位系统项目:

.toolbar {
    DefaultToolbarItem(kind: .search, placement: .bottomBar)
    DefaultToolbarItem(kind: .sidebar, placement: .navigationBarLeading)
}

Large Subtitle 放置位置

在导航栏副标题区域放置自定义内容:

NavigationStack {
    DetailView()
        .navigationTitle("Title")
        .navigationSubtitle("Subtitle")
        .toolbar {
            ToolbarItem(placement: .largeSubtitle) {
                CustomLargeNavigationSubtitle()
            }
        }
}

过渡效果

从工具栏开始的匹配过渡

创建从工具栏按钮发起的缩放过渡:

struct ContentView: View {
    @State private var isPresented = false
    @Namespace private var namespace

    var body: some View {
        NavigationStack {
            DetailView()
                .toolbar {
                    ToolbarItem(placement: .topBarTrailing) {
                        Button("Show Sheet", systemImage: "globe") {
                            isPresented = true
                        }
                    }
                    .matchedTransitionSource(id: "world", in: namespace)
                }
                .sheet(isPresented: $isPresented) {
                    SheetView()
                        .navigationTransition(
                            .zoom(sourceID: "world", in: namespace))
                }
        }
    }
}
玻璃背景控制

控制工具栏项目共享的玻璃背景:

ContentView()
    .toolbar(id: "main") {
        ToolbarItem(id: "build-status", placement: .principal) {
            BuildStatus()
        }
        .sharedBackgroundVisibility(.hidden)
    }

最常见的 5 个错误

#错误修正方法
1可自定义工具栏中的 ToolbarItem 缺少 id.toolbar(id:) 中的每个项目都必须有自己的 id 参数
2不使用 .searchable() 却使用 .searchToolbarBehavior(.minimize)必须与 .searchable() 修饰符配合使用——.minimize 只影响显示方式
3将 .matchedTransitionSource 添加到 Button 而不是 ToolbarItem 上在 ToolbarItem 上应用 .matchedTransitionSource(id:in:),而不是添加到其内容上
4同时使用 .largeSubtitle 和 .navigationSubtitle(),并期望两者都显示.largeSubtitle 优先级更高——副标题修饰符的值会被隐藏
5忘记为 DefaultToolbarItem 指定 placement:未显式指定时,系统项目会使用其默认位置

平台注意事项

平台建议
iOS底部栏在 iPhone 上很实用。使用 .searchToolbarBehavior(.minimize) 提高空间利用率。
iPadOS可自定义工具栏对效率类应用很有价值。可考虑添加键盘快捷键。
macOS用户期望工具栏可自定义。使用间隔器对项目进行逻辑分组。

检查清单

可自定义工具栏
  • .toolbar(id:) 使用唯一且稳定的字符串标识符
  • 其中的每个 ToolbarItem 都有自己的唯一 id
  • 使用间隔器对相关项目进行逻辑分组
  • 使用自定义面板测试工具栏(在 iPadOS 上长按,在 macOS 上右键单击)
搜索集成
  • 将 .searchable() 与适当的 .searchToolbarBehavior() 配合使用
  • 搜索位置应适合平台(iOS 上为底部栏,macOS 上为工具栏)
  • 需要调整位置时,使用 DefaultToolbarItem(kind: .search)
转场
  • 将 .matchedTransitionSource 应用于 ToolbarItem,而不是其内容视图
  • 在视图层级使用 @Namespace 声明命名空间
  • .matchedTransitionSource 与 .navigationTransition(.zoom) 中的源 ID 保持一致
平台
  • 在 iOS 和 macOS 上测试工具栏布局(如果是多平台应用)
  • 底部栏项应适合小屏幕
  • 为复杂的 macOS 应用提供可自定义工具栏

参考资料

评论

支持 Markdown