toolbars

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SwiftUI Toolbars

SwiftUI 工具栏

Modern toolbar patterns for SwiftUI apps. Covers customizable toolbars, enhanced search integration, new placements, transition effects, and platform-specific considerations.
适用于SwiftUI应用的现代工具栏模式,涵盖可自定义工具栏、增强型搜索集成、新布局位置、过渡效果以及平台特定注意事项。

When This Skill Activates

技能适用场景

Use this skill when the user:
  • Wants to add or customize toolbars
  • Asks about customizable/user-configurable toolbars
  • Needs search field in toolbar with specific placement
  • Wants toolbar item transitions or animations
  • Asks about toolbar placements (bottomBar, largeSubtitle, etc.)
  • Needs platform-specific toolbar behavior (iOS vs macOS)
  • Wants to reposition system toolbar items (search, sidebar)
当用户有以下需求时使用本技能:
  • 想要添加或自定义工具栏
  • 询问可自定义/用户可配置的工具栏相关问题
  • 需要在工具栏中特定位置添加搜索框
  • 想要实现工具栏项的过渡或动画效果
  • 询问工具栏布局位置(如bottomBar、largeSubtitle等)
  • 需要适配平台的工具栏行为(iOS与macOS对比)
  • 想要重新调整系统工具栏项的位置(如搜索、侧边栏)

Decision Tree

决策树

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:)
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 Availability

API 可用性

APIMinimum VersionNotes
.toolbar { }
iOS 14Basic toolbar
ToolbarItem(placement:)
iOS 14Standard placements
.toolbar(id:)
iOS 16Customizable toolbars
ToolbarItem(id:)
iOS 16Items in customizable toolbars
ToolbarSpacer
iOS 16Fixed and flexible spacers
.searchable()
iOS 15Search integration
.searchToolbarBehavior(.minimize)
iOS 17Minimized search button
DefaultToolbarItem(kind:placement:)
iOS 18Reposition system items
ToolbarItem(placement: .largeSubtitle)
iOS 18Subtitle area content
.matchedTransitionSource(id:in:)
iOS 18Toolbar transition source
.sharedBackgroundVisibility()
iOS 18Glass background control
API最低版本说明
.toolbar { }
iOS 14基础工具栏
ToolbarItem(placement:)
iOS 14标准布局位置
.toolbar(id:)
iOS 16可自定义工具栏
ToolbarItem(id:)
iOS 16可自定义工具栏中的项
ToolbarSpacer
iOS 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毛玻璃背景控制

Customizable Toolbars

可自定义工具栏

Allow users to personalize toolbar items by adding, removing, and rearranging:
swift
ContentView()
    .toolbar(id: "main-toolbar") {
        ToolbarItem(id: "tag") {
            TagButton()
        }
        ToolbarItem(id: "share") {
            ShareButton()
        }
        ToolbarSpacer(.fixed)
        ToolbarItem(id: "more") {
            MoreButton()
        }
    }
允许用户通过添加、删除和重新排列工具栏项来个性化定制:
swift
ContentView()
    .toolbar(id: "main-toolbar") {
        ToolbarItem(id: "tag") {
            TagButton()
        }
        ToolbarItem(id: "share") {
            ShareButton()
        }
        ToolbarSpacer(.fixed)
        ToolbarItem(id: "more") {
            MoreButton()
        }
    }

Toolbar Spacers

工具栏间距控件

swift
ToolbarSpacer(.fixed)      // Fixed-width space
ToolbarSpacer(.flexible)   // Flexible space — pushes items apart
swift
ToolbarSpacer(.fixed)      // 固定宽度的间距
ToolbarSpacer(.flexible)   // 灵活间距——将项分开

Anti-Patterns

反模式

swift
// ❌ 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()
    }
}
swift
// ❌ 可自定义工具栏中缺少ID——项无法被定制
.toolbar(id: "main") {
    ToolbarItem {           // 缺少id参数
        ShareButton()
    }
}

// ✅ 每个项都需要有自己的ID
.toolbar(id: "main") {
    ToolbarItem(id: "share") {
        ShareButton()
    }
}

Enhanced Search Integration

增强型搜索集成

Minimized Search

最小化搜索

Renders search field as a compact button that expands on tap:
swift
@State private var searchText = ""

NavigationStack {
    RecipeList()
        .searchable(text: $searchText)
        .searchToolbarBehavior(.minimize)
}
将搜索框渲染为紧凑按钮,点击后展开:
swift
@State private var searchText = ""

NavigationStack {
    RecipeList()
        .searchable(text: $searchText)
        .searchToolbarBehavior(.minimize)
}

Repositioning Search

重新调整搜索位置

Move the default search field to a different toolbar position:
swift
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()
            }
        }
}
将默认搜索框移动到工具栏的其他位置:
swift
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()
            }
        }
}

System-Defined Toolbar Items

系统定义的工具栏项

Reposition system items with custom placements:
swift
.toolbar {
    DefaultToolbarItem(kind: .search, placement: .bottomBar)
    DefaultToolbarItem(kind: .sidebar, placement: .navigationBarLeading)
}
通过自定义布局位置重新调整系统项:
swift
.toolbar {
    DefaultToolbarItem(kind: .search, placement: .bottomBar)
    DefaultToolbarItem(kind: .sidebar, placement: .navigationBarLeading)
}

Large Subtitle Placement

大副标题布局位置

Place custom content in the navigation bar subtitle area:
swift
NavigationStack {
    DetailView()
        .navigationTitle("Title")
        .navigationSubtitle("Subtitle")
        .toolbar {
            ToolbarItem(placement: .largeSubtitle) {
                CustomLargeNavigationSubtitle()
            }
        }
}
The
.largeSubtitle
placement takes precedence over the value provided to
navigationSubtitle(_:)
.
在导航栏副标题区域放置自定义内容:
swift
NavigationStack {
    DetailView()
        .navigationTitle("Title")
        .navigationSubtitle("Subtitle")
        .toolbar {
            ToolbarItem(placement: .largeSubtitle) {
                CustomLargeNavigationSubtitle()
            }
        }
}
.largeSubtitle
布局位置的优先级高于
navigationSubtitle(_:)
设置的值。

Transition Effects

过渡效果

Matched Transition from Toolbar

工具栏匹配过渡

Create zoom transitions originating from a toolbar button:
swift
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))
                }
        }
    }
}
创建从工具栏按钮发起的缩放过渡效果:
swift
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))
                }
        }
    }
}

Glass Background Control

毛玻璃背景控制

Control the shared glass background on toolbar items:
swift
ContentView()
    .toolbar(id: "main") {
        ToolbarItem(id: "build-status", placement: .principal) {
            BuildStatus()
        }
        .sharedBackgroundVisibility(.hidden)
    }
控制工具栏项的共享毛玻璃背景:
swift
ContentView()
    .toolbar(id: "main") {
        ToolbarItem(id: "build-status", placement: .principal) {
            BuildStatus()
        }
        .sharedBackgroundVisibility(.hidden)
    }

Top 5 Mistakes

五大常见错误

#MistakeFix
1Missing
id
on ToolbarItem in customizable toolbar
Every item in
.toolbar(id:)
must have its own
id
parameter
2Using
.searchToolbarBehavior(.minimize)
without
.searchable()
Must pair with
.searchable()
modifier —
.minimize
only affects rendering
3Putting
.matchedTransitionSource
on the Button instead of ToolbarItem
Apply
.matchedTransitionSource(id:in:)
on the
ToolbarItem
, not its content
4Using
.largeSubtitle
alongside
.navigationSubtitle()
expecting both to show
.largeSubtitle
takes precedence — the subtitle modifier value is hidden
5Forgetting
placement:
on DefaultToolbarItem
Without explicit placement, system items use their default position
#错误修复方案
1可自定义工具栏中的ToolbarItem缺少id可自定义工具栏中的每个
ToolbarItem
必须拥有自己的
id
参数
2在未使用
.searchable()
的情况下使用
.searchToolbarBehavior(.minimize)
必须与
.searchable()
修饰符配合使用——
.minimize
仅影响渲染效果
3
.matchedTransitionSource
应用于Button而非ToolbarItem
.matchedTransitionSource(id:in:)
应用于
ToolbarItem
,而非其内部内容
4同时使用
.largeSubtitle
.navigationSubtitle()
并期望两者都显示
.largeSubtitle
优先级更高——
navigationSubtitle
修饰符设置的值会被隐藏
5DefaultToolbarItem遗漏
placement:
参数
如果不明确指定布局位置,系统项会使用默认位置

Platform Considerations

平台注意事项

PlatformRecommendations
iOSBottom bar useful on iPhones. Use
.searchToolbarBehavior(.minimize)
for space efficiency.
iPadOSCustomizable toolbars valuable in productivity apps. Consider keyboard shortcuts.
macOSUsers expect toolbar customization. Use spacers for logical groupings.
平台建议
iOS底部工具栏在iPhone上很实用。使用
.searchToolbarBehavior(.minimize)
节省空间。
iPadOS可自定义工具栏在生产力应用中很有价值。考虑添加键盘快捷键。
macOS用户期望工具栏可自定义。使用间距控件进行逻辑分组。

Review Checklist

检查清单

Customizable Toolbars

可自定义工具栏

  • .toolbar(id:)
    has a unique, stable string identifier
  • Every
    ToolbarItem
    within has its own unique
    id
  • Spacers used to create logical groups of related items
  • Toolbar tested with customization panel (long-press on iPadOS, right-click on macOS)
  • .toolbar(id:)
    使用唯一且稳定的字符串标识符
  • 内部每个
    ToolbarItem
    都有自己的唯一
    id
  • 使用间距控件对相关项进行逻辑分组
  • 使用定制面板测试工具栏(iPadOS上长按,macOS上右键点击)

Search Integration

搜索集成

  • .searchable()
    paired with appropriate
    .searchToolbarBehavior()
  • Search placement makes sense for the platform (bottom bar on iOS, toolbar on macOS)
  • DefaultToolbarItem(kind: .search)
    used when repositioning is needed
  • .searchable()
    与合适的
    .searchToolbarBehavior()
    配合使用
  • 搜索框的布局位置符合平台特性(iOS用底部工具栏,macOS用工具栏)
  • 需要重新调整位置时使用
    DefaultToolbarItem(kind: .search)

Transitions

过渡效果

  • .matchedTransitionSource
    applied to
    ToolbarItem
    , not its content view
  • Namespace declared with
    @Namespace
    at the view level
  • Source ID matches between
    .matchedTransitionSource
    and
    .navigationTransition(.zoom)
  • .matchedTransitionSource
    应用于
    ToolbarItem
    ,而非其内容视图
  • 在视图级别使用
    @Namespace
    声明命名空间
  • .matchedTransitionSource
    .navigationTransition(.zoom)
    的源ID保持一致

Platform

平台适配

  • Toolbar layouts tested on both iOS and macOS (if multiplatform)
  • Bottom bar items appropriate for small screens
  • Customizable toolbars provided for complex macOS apps
  • 工具栏布局在iOS和macOS上都经过测试(如果是多平台应用)
  • 底部工具栏项适合小屏幕
  • 为复杂的macOS应用提供可自定义工具栏

References

参考资料