macos-hig-designer
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesemacOS HIG Designer
macOS HIG 设计手册
Design native macOS applications following Apple's Human Interface Guidelines with macOS Tahoe's Liquid Glass design system.
遵循Apple人机界面指南,结合macOS Tahoe的Liquid Glass设计系统,设计原生macOS应用。
Workflow Decision Tree
工作流决策树
User Request
│
├─► "Review my macOS UI code"
│ └─► Run HIG Compliance Check (Section 11)
│ └─► Report violations with fixes
│
├─► "Modernize this macOS code"
│ └─► Identify deprecated APIs
│ └─► Apply Modern API Replacements (Section 10)
│
└─► "Build [feature] for macOS"
└─► Design with HIG principles first
└─► Implement with modern SwiftUI patterns用户需求
│
├─► "审核我的macOS UI代码"
│ └─► 执行HIG合规性检查(第11节)
│ └─► 报告违规问题并提供修复方案
│
├─► "升级我的macOS代码"
│ └─► 识别已弃用的API
│ └─► 应用现代API替代方案(第10节)
│
└─► "为macOS构建[功能]"
└─► 首先遵循HIG原则进行设计
└─► 使用现代SwiftUI模式实现1. Design Principles (macOS Tahoe)
1. 设计原则(macOS Tahoe)
Three Core Tenets
三大核心准则
| Principle | Description | Implementation |
|---|---|---|
| Hierarchy | Visual layers through Liquid Glass translucency | Use |
| Harmony | Concentric alignment between hardware/software | Round corners, consistent radii, flowing shapes |
| Consistency | Platform conventions that adapt to context | Follow standard patterns, respect user preferences |
| 设计原则 | 说明 | 实现方式 |
|---|---|---|
| 层级结构 | 通过Liquid Glass半透明效果实现视觉层级 | 使用 |
| 和谐统一 | 硬件与软件之间的同心对齐 | 圆角、统一半径、流畅形状 |
| 一致性 | 适配上下文的平台惯例 | 遵循标准模式,尊重用户偏好 |
Liquid Glass Philosophy
Liquid Glass 设计理念
Liquid Glass combines transparency, reflection, refraction, and fluidity with a frosted aesthetic:
swift
// macOS Tahoe Liquid Glass effect
.glassEffect() // Primary Liquid Glass material
.glassEffect(.regular.tinted) // Tinted variant (26.1+)
// Pre-Tahoe fallback
.background(.ultraThinMaterial)
.background(.regularMaterial)
.background(.thickMaterial)When to use Liquid Glass:
- Sidebars, toolbars, and navigation chrome
- Floating panels and popovers
- Dock and widget backgrounds
- System-level UI elements
When NOT to use:
- Primary content areas (documents, media)
- Dense data displays (tables, lists with many items)
- Text-heavy interfaces where readability is critical
Liquid Glass 将透明度、反射、折射和流动性与磨砂美学相结合:
swift
// macOS Tahoe Liquid Glass 效果
.glassEffect() // 核心Liquid Glass材质
.glassEffect(.regular.tinted) // 着色变体(26.1+)
// Tahoe版本之前的兼容方案
.background(.ultraThinMaterial)
.background(.regularMaterial)
.background(.thickMaterial)Liquid Glass 适用场景:
- 侧边栏、工具栏和导航栏
- 浮动面板和弹出框
- 程序坞和小组件背景
- 系统级UI元素
Liquid Glass 不适用场景:
- 主要内容区域(文档、媒体)
- 密集数据展示(表格、包含大量条目的列表)
- 可读性要求高的文本密集型界面
2. Navigation Patterns
2. 导航模式
NavigationSplitView (Primary Pattern)
NavigationSplitView(核心模式)
Three-column layout for document-based and content-heavy apps:
swift
struct ContentView: View {
@State private var selection: Item.ID?
@State private var columnVisibility: NavigationSplitViewVisibility = .all
var body: some View {
NavigationSplitView(columnVisibility: $columnVisibility) {
// Sidebar (source list)
List(items, selection: $selection) { item in
NavigationLink(value: item) {
Label(item.title, systemImage: item.icon)
}
}
.navigationSplitViewColumnWidth(min: 180, ideal: 220, max: 300)
} content: {
// Content column (optional middle)
ContentListView(selection: selection)
} detail: {
// Detail view
DetailView(item: selectedItem)
}
}
}适用于文档类和内容密集型应用的三栏布局:
swift
struct ContentView: View {
@State private var selection: Item.ID?
@State private var columnVisibility: NavigationSplitViewVisibility = .all
var body: some View {
NavigationSplitView(columnVisibility: $columnVisibility) {
// 侧边栏(源列表)
List(items, selection: $selection) { item in
NavigationLink(value: item) {
Label(item.title, systemImage: item.icon)
}
}
.navigationSplitViewColumnWidth(min: 180, ideal: 220, max: 300)
} content: {
// 内容栏(可选中间栏)
ContentListView(selection: selection)
} detail: {
// 详情视图
DetailView(item: selectedItem)
}
}
}Sidebar Patterns
侧边栏模式
swift
// Source list with sections
List(selection: $selection) {
Section("Library") {
ForEach(libraryItems) { item in
Label(item.name, systemImage: item.icon)
.tag(item)
}
}
Section("Collections") {
ForEach(collections) { collection in
Label(collection.name, systemImage: "folder")
.tag(collection)
.badge(collection.count)
}
}
}
.listStyle(.sidebar)swift
// 带分组的源列表
List(selection: $selection) {
Section("库") {
ForEach(libraryItems) { item in
Label(item.name, systemImage: item.icon)
.tag(item)
}
}
Section("集合") {
ForEach(collections) { collection in
Label(collection.name, systemImage: "folder")
.tag(collection)
.badge(collection.count)
}
}
}
.listStyle(.sidebar)Inspector Panel (Trailing Sidebar)
检查器面板(右侧边栏)
swift
struct DocumentView: View {
@State private var showInspector = true
var body: some View {
MainContentView()
.inspector(isPresented: $showInspector) {
InspectorView()
.inspectorColumnWidth(min: 200, ideal: 250, max: 400)
}
.toolbar {
ToolbarItem {
Button {
showInspector.toggle()
} label: {
Label("Inspector", systemImage: "sidebar.trailing")
}
}
}
}
}swift
struct DocumentView: View {
@State private var showInspector = true
var body: some View {
MainContentView()
.inspector(isPresented: $showInspector) {
InspectorView()
.inspectorColumnWidth(min: 200, ideal: 250, max: 400)
}
.toolbar {
ToolbarItem {
Button {
showInspector.toggle()
} label: {
Label("检查器", systemImage: "sidebar.trailing")
}
}
}
}
}3. Window Management
3. 窗口管理
Window Configuration
窗口配置
swift
@main
struct MyApp: App {
var body: some Scene {
// Main document window
WindowGroup {
ContentView()
}
.windowStyle(.automatic)
.windowToolbarStyle(.unified)
.defaultSize(width: 900, height: 600)
.defaultPosition(.center)
// Settings window
Settings {
SettingsView()
}
// Utility window
Window("Inspector", id: "inspector") {
InspectorWindow()
}
.windowStyle(.plain)
.windowResizability(.contentSize)
.defaultPosition(.topTrailing)
// Menu bar extra
MenuBarExtra("Status", systemImage: "circle.fill") {
StatusMenu()
}
.menuBarExtraStyle(.window)
}
}swift
@main
struct MyApp: App {
var body: some Scene {
// 主文档窗口
WindowGroup {
ContentView()
}
.windowStyle(.automatic)
.windowToolbarStyle(.unified)
.defaultSize(width: 900, height: 600)
.defaultPosition(.center)
// 设置窗口
Settings {
SettingsView()
}
// 工具窗口
Window("检查器", id: "inspector") {
InspectorWindow()
}
.windowStyle(.plain)
.windowResizability(.contentSize)
.defaultPosition(.topTrailing)
// 菜单栏额外项
MenuBarExtra("状态", systemImage: "circle.fill") {
StatusMenu()
}
.menuBarExtraStyle(.window)
}
}Window Styles
窗口样式
| Style | Use Case |
|---|---|
| Standard app windows |
| Content-focused (media players) |
| Utility windows, panels |
| Integrated toolbar appearance |
| Compact toolbar height |
| 样式 | 适用场景 |
|---|---|
| 标准应用窗口 |
| 内容优先型(媒体播放器) |
| 工具窗口、面板 |
| 集成式工具栏外观 |
| 紧凑工具栏高度 |
Window State Restoration
窗口状态恢复
swift
WindowGroup {
ContentView()
}
.handlesExternalEvents(matching: Set(arrayLiteral: "main"))
.commands {
CommandGroup(replacing: .newItem) {
Button("New Document") {
// Handle new document
}
.keyboardShortcut("n")
}
}swift
WindowGroup {
ContentView()
}
.handlesExternalEvents(matching: Set(arrayLiteral: "main"))
.commands {
CommandGroup(replacing: .newItem) {
Button("新建文档") {
// 处理新建文档逻辑
}
.keyboardShortcut("n")
}
}Document-Based Apps
文档类应用
swift
@main
struct DocumentApp: App {
var body: some Scene {
DocumentGroup(newDocument: MyDocument()) { file in
DocumentView(document: file.$document)
}
.commands {
CommandGroup(after: .saveItem) {
Button("Export...") { }
.keyboardShortcut("e", modifiers: [.command, .shift])
}
}
}
}
struct MyDocument: FileDocument {
static var readableContentTypes: [UTType] { [.plainText] }
init(configuration: ReadConfiguration) throws { }
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper { }
}swift
@main
struct DocumentApp: App {
var body: some Scene {
DocumentGroup(newDocument: MyDocument()) { file in
DocumentView(document: file.$document)
}
.commands {
CommandGroup(after: .saveItem) {
Button("导出...") { }
.keyboardShortcut("e", modifiers: [.command, .shift])
}
}
}
}
struct MyDocument: FileDocument {
static var readableContentTypes: [UTType] { [.plainText] }
init(configuration: ReadConfiguration) throws { }
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper { }
}4. Toolbar & Menu Bar
4. 工具栏与菜单栏
Toolbar Configuration
工具栏配置
swift
.toolbar {
// Leading items (macOS places these before title)
ToolbarItem(placement: .navigation) {
Button(action: goBack) {
Label("Back", systemImage: "chevron.left")
}
}
// Principal (centered)
ToolbarItem(placement: .principal) {
Picker("View Mode", selection: $viewMode) {
Label("Icons", systemImage: "square.grid.2x2").tag(ViewMode.icons)
Label("List", systemImage: "list.bullet").tag(ViewMode.list)
}
.pickerStyle(.segmented)
}
// Trailing items
ToolbarItemGroup(placement: .primaryAction) {
Button(action: share) {
Label("Share", systemImage: "square.and.arrow.up")
}
Button(action: toggleInspector) {
Label("Inspector", systemImage: "sidebar.trailing")
}
}
}
.toolbarRole(.editor) // or .browser, .automaticswift
.toolbar {
// 左侧项(macOS会将这些放在标题前)
ToolbarItem(placement: .navigation) {
Button(action: goBack) {
Label("返回", systemImage: "chevron.left")
}
}
// 主项(居中)
ToolbarItem(placement: .principal) {
Picker("视图模式", selection: $viewMode) {
Label("图标", systemImage: "square.grid.2x2").tag(ViewMode.icons)
Label("列表", systemImage: "list.bullet").tag(ViewMode.list)
}
.pickerStyle(.segmented)
}
// 右侧项
ToolbarItemGroup(placement: .primaryAction) {
Button(action: share) {
Label("分享", systemImage: "square.and.arrow.up")
}
Button(action: toggleInspector) {
Label("检查器", systemImage: "sidebar.trailing")
}
}
}
.toolbarRole(.editor) // 或 .browser、.automaticCustom Menu Bar
自定义菜单栏
swift
.commands {
// Replace existing menu group
CommandGroup(replacing: .newItem) {
Button("New Project") { }
.keyboardShortcut("n")
Button("New from Template...") { }
.keyboardShortcut("n", modifiers: [.command, .shift])
}
// Add to existing group
CommandGroup(after: .sidebar) {
Button("Toggle Inspector") { }
.keyboardShortcut("i", modifiers: [.command, .option])
}
// Custom menu
CommandMenu("Canvas") {
Button("Zoom In") { }
.keyboardShortcut("+")
Button("Zoom Out") { }
.keyboardShortcut("-")
Divider()
Button("Fit to Window") { }
.keyboardShortcut("0")
}
}swift
.commands {
// 替换现有菜单组
CommandGroup(replacing: .newItem) {
Button("新建项目") { }
.keyboardShortcut("n")
Button("从模板新建...") { }
.keyboardShortcut("n", modifiers: [.command, .shift])
}
// 添加到现有组
CommandGroup(after: .sidebar) {
Button("切换检查器") { }
.keyboardShortcut("i", modifiers: [.command, .option])
}
// 自定义菜单
CommandMenu("画布") {
Button("放大") { }
.keyboardShortcut("+")
Button("缩小") { }
.keyboardShortcut("-")
Divider()
Button("适应窗口") { }
.keyboardShortcut("0")
}
}Menu Bar Apps
菜单栏应用
swift
MenuBarExtra("App Status", systemImage: statusIcon) {
VStack(alignment: .leading, spacing: 8) {
Text("Status: \(status)")
.font(.headline)
Divider()
Button("Open Main Window") {
openWindow(id: "main")
}
Button("Quit") {
NSApplication.shared.terminate(nil)
}
.keyboardShortcut("q")
}
.padding()
}
.menuBarExtraStyle(.window) // or .menu for simple dropdownswift
MenuBarExtra("应用状态", systemImage: statusIcon) {
VStack(alignment: .leading, spacing: 8) {
Text("状态:\(status)")
.font(.headline)
Divider()
Button("打开主窗口") {
openWindow(id: "main")
}
Button("退出") {
NSApplication.shared.terminate(nil)
}
.keyboardShortcut("q")
}
.padding()
}
.menuBarExtraStyle(.window) // 或 .menu 用于简单下拉菜单5. Keyboard Shortcuts
5. 键盘快捷键
Standard macOS Shortcuts
标准macOS快捷键
Always implement these when applicable:
| Action | Shortcut | Implementation |
|---|---|---|
| New | ⌘N | |
| Open | ⌘O | |
| Save | ⌘S | |
| Close | ⌘W | |
| Undo | ⌘Z | |
| Redo | ⇧⌘Z | |
| Cut | ⌘X | |
| Copy | ⌘C | |
| Paste | ⌘V | |
| Select All | ⌘A | |
| Find | ⌘F | |
| Preferences | ⌘, | |
| Hide | ⌘H | System handled |
| Quit | ⌘Q | System handled |
适用时请务必实现以下快捷键:
| 操作 | 快捷键 | 实现方式 |
|---|---|---|
| 新建 | ⌘N | |
| 打开 | ⌘O | |
| 保存 | ⌘S | |
| 关闭 | ⌘W | |
| 撤销 | ⌘Z | |
| 重做 | ⇧⌘Z | |
| 剪切 | ⌘X | |
| 复制 | ⌘C | |
| 粘贴 | ⌘V | |
| 全选 | ⌘A | |
| 查找 | ⌘F | |
| 偏好设置 | ⌘, | |
| 隐藏 | ⌘H | 系统自动处理 |
| 退出 | ⌘Q | 系统自动处理 |
Custom Shortcuts
自定义快捷键
swift
Button("Toggle Sidebar") {
toggleSidebar()
}
.keyboardShortcut("s", modifiers: [.command, .control])
// Function keys
Button("Refresh") { }
.keyboardShortcut(KeyEquivalent.init(Character(UnicodeScalar(NSF5FunctionKey)!)))
// Arrow keys
Button("Next") { }
.keyboardShortcut(.rightArrow)swift
Button("切换侧边栏") {
toggleSidebar()
}
.keyboardShortcut("s", modifiers: [.command, .control])
// 功能键
Button("刷新") { }
.keyboardShortcut(KeyEquivalent.init(Character(UnicodeScalar(NSF5FunctionKey)!)))
// 方向键
Button("下一个") { }
.keyboardShortcut(.rightArrow)6. Components with Liquid Glass
6. 带Liquid Glass效果的组件
Control Sizing
控件尺寸
| Size | Shape | Use Case |
|---|---|---|
| Mini | Rounded rect | Compact toolbars, dense UIs |
| Small | Rounded rect | Secondary controls, sidebars |
| Regular | Rounded rect | Primary controls (default) |
| Large | Capsule | Prominent actions |
| Extra Large | Capsule + Glass | Hero CTAs, onboarding |
swift
// Size modifiers
Button("Action") { }
.controlSize(.mini) // Smallest
.controlSize(.small) // Compact
.controlSize(.regular) // Default
.controlSize(.large) // Prominent
.controlSize(.extraLarge) // Hero (macOS 15+)| 尺寸 | 形状 | 适用场景 |
|---|---|---|
| Mini | 圆角矩形 | 紧凑工具栏、密集UI |
| Small | 圆角矩形 | 次要控件、侧边栏 |
| Regular | 圆角矩形 | 主要控件(默认) |
| Large | 胶囊形 | 突出操作 |
| Extra Large | 胶囊形+玻璃效果 | 核心CTA、引导页 |
swift
// 尺寸修饰符
Button("操作") { }
.controlSize(.mini) // 最小尺寸
.controlSize(.small) // 紧凑尺寸
.controlSize(.regular) // 默认尺寸
.controlSize(.large) // 突出尺寸
.controlSize(.extraLarge) // 核心尺寸(macOS 15+)Buttons
按钮
swift
// Primary action (prominent)
Button("Save Changes") { }
.buttonStyle(.borderedProminent)
.controlSize(.large)
// Secondary action
Button("Cancel") { }
.buttonStyle(.bordered)
// Tertiary/link style
Button("Learn More") { }
.buttonStyle(.plain)
.foregroundStyle(.link)
// Destructive
Button("Delete", role: .destructive) { }
.buttonStyle(.bordered)
// Toolbar button
Button { } label: {
Label("Add", systemImage: "plus")
}
.buttonStyle(.borderless)swift
// 主要操作(突出显示)
Button("保存更改") { }
.buttonStyle(.borderedProminent)
.controlSize(.large)
// 次要操作
Button("取消") { }
.buttonStyle(.bordered)
// 三级/链接样式
Button("了解更多") { }
.buttonStyle(.plain)
.foregroundStyle(.link)
// 破坏性操作
Button("删除", role: .destructive) { }
.buttonStyle(.bordered)
// 工具栏按钮
Button { } label: {
Label("添加", systemImage: "plus")
}
.buttonStyle(.borderless)Text Fields
文本框
swift
// Standard text field
TextField("Search", text: $query)
.textFieldStyle(.roundedBorder)
// Search field with tokens
TextField("Search", text: $query)
.searchable(text: $query, tokens: $tokens) { token in
Label(token.name, systemImage: token.icon)
}
// Secure field
SecureField("Password", text: $password)
.textFieldStyle(.roundedBorder)swift
// 标准文本框
TextField("搜索", text: $query)
.textFieldStyle(.roundedBorder)
// 带标记的搜索框
TextField("搜索", text: $query)
.searchable(text: $query, tokens: $tokens) { token in
Label(token.name, systemImage: token.icon)
}
// 密码框
SecureField("密码", text: $password)
.textFieldStyle(.roundedBorder)Tables
表格
swift
Table(items, selection: $selection) {
TableColumn("Name", value: \.name)
.width(min: 100, ideal: 150)
TableColumn("Date") { item in
Text(item.date, format: .dateTime)
}
.width(100)
TableColumn("Status") { item in
StatusBadge(status: item.status)
}
.width(80)
}
.tableStyle(.inset(alternatesRowBackgrounds: true))
.contextMenu(forSelectionType: Item.ID.self) { selection in
Button("Open") { }
Button("Delete", role: .destructive) { }
}swift
Table(items, selection: $selection) {
TableColumn("名称", value: \.name)
.width(min: 100, ideal: 150)
TableColumn("日期") { item in
Text(item.date, format: .dateTime)
}
.width(100)
TableColumn("状态") { item in
StatusBadge(status: item.status)
}
.width(80)
}
.tableStyle(.inset(alternatesRowBackgrounds: true))
.contextMenu(forSelectionType: Item.ID.self) { selection in
Button("打开") { }
Button("删除", role: .destructive) { }
}Popovers and Sheets
弹出框与表单页
swift
// Popover
Button("Info") {
showPopover = true
}
.popover(isPresented: $showPopover, arrowEdge: .bottom) {
InfoView()
.frame(width: 300, height: 200)
.padding()
}
// Sheet
.sheet(isPresented: $showSheet) {
SheetContent()
.frame(minWidth: 400, minHeight: 300)
}
// Alert
.alert("Delete Item?", isPresented: $showAlert) {
Button("Cancel", role: .cancel) { }
Button("Delete", role: .destructive) {
deleteItem()
}
} message: {
Text("This action cannot be undone.")
}swift
// 弹出框
Button("信息") {
showPopover = true
}
.popover(isPresented: $showPopover, arrowEdge: .bottom) {
InfoView()
.frame(width: 300, height: 200)
.padding()
}
// 表单页
.sheet(isPresented: $showSheet) {
SheetContent()
.frame(minWidth: 400, minHeight: 300)
}
// 警告框
.alert("确定要删除该项目?", isPresented: $showAlert) {
Button("取消", role: .cancel) { }
Button("删除", role: .destructive) {
deleteItem()
}
} message: {
Text("此操作无法撤销。")
}7. Typography & Colors
7. 排版与颜色
System Typography
系统排版
swift
// Semantic styles (preferred)
Text("Title").font(.largeTitle) // 26pt bold
Text("Headline").font(.headline) // 13pt semibold
Text("Subheadline").font(.subheadline) // 11pt regular
Text("Body").font(.body) // 13pt regular
Text("Callout").font(.callout) // 12pt regular
Text("Caption").font(.caption) // 10pt regular
Text("Caption 2").font(.caption2) // 10pt regular
// Monospaced for code
Text("let x = 1").font(.system(.body, design: .monospaced))swift
// 语义化样式(推荐)
Text("标题").font(.largeTitle) // 26pt 粗体
Text("主标题").font(.headline) // 13pt 半粗体
Text("副标题").font(.subheadline) // 11pt 常规
Text("正文").font(.body) // 13pt 常规
Text("标注").font(.callout) // 12pt 常规
Text("说明文字").font(.caption) // 10pt 常规
Text("次要说明").font(.caption2) // 10pt 常规
// 代码用等宽字体
Text("let x = 1").font(.system(.body, design: .monospaced))Semantic Colors
语义化颜色
swift
// Foreground
.foregroundStyle(.primary) // Primary text
.foregroundStyle(.secondary) // Secondary text
.foregroundStyle(.tertiary) // Tertiary text
.foregroundStyle(.quaternary) // Quaternary text
// Backgrounds
.background(.background) // Window background
.background(.regularMaterial) // Translucent material
// Accent colors
.tint(.accentColor) // App accent color
.foregroundStyle(.link) // Clickable links
// Semantic colors
Color.red // System red (adapts to light/dark)
Color.blue // System blueswift
// 前景色
.foregroundStyle(.primary) // 主要文本色
.foregroundStyle(.secondary) // 次要文本色
.foregroundStyle(.tertiary) // 三级文本色
.foregroundStyle(.quaternary) // 四级文本色
// 背景色
.background(.background) // 窗口背景色
.background(.regularMaterial) // 半透明材质
// 强调色
.tint(.accentColor) // 应用强调色
.foregroundStyle(.link) // 可点击链接色
// 语义化颜色
Color.red // 系统红色(适配明暗模式)
Color.blue // 系统蓝色Vibrancy and Materials
活力效果与材质
swift
// Materials (adapt to background content)
.background(.ultraThinMaterial) // Most transparent
.background(.thinMaterial)
.background(.regularMaterial) // Default
.background(.thickMaterial)
.background(.ultraThickMaterial) // Least transparent
// Vibrancy in sidebars
List { }
.listStyle(.sidebar)
.scrollContentBackground(.hidden)
.background(.ultraThinMaterial)swift
// 材质(适配背景内容)
.background(.ultraThinMaterial) // 最透明
.background(.thinMaterial)
.background(.regularMaterial) // 默认
.background(.thickMaterial)
.background(.ultraThickMaterial) // 最不透明
// 侧边栏活力效果
List { }
.listStyle(.sidebar)
.scrollContentBackground(.hidden)
.background(.ultraThinMaterial)8. Spacing & Layout
8. 间距与布局
8-Point Grid System
8点网格系统
swift
// Standard spacing values
VStack(spacing: 8) { } // Standard
VStack(spacing: 16) { } // Section spacing
VStack(spacing: 20) { } // Group spacing
// Padding
.padding(8) // Tight
.padding(12) // Standard
.padding(16) // Comfortable
.padding(20) // Spacious
// Content margins
.contentMargins(16) // Uniform margins
.contentMargins(.horizontal, 20) // Horizontal onlyswift
// 标准间距值
VStack(spacing: 8) { } // 标准间距
VStack(spacing: 16) { } // 区块间距
VStack(spacing: 20) { } // 组间距
// 内边距
.padding(8) // 紧凑
.padding(12) // 标准
.padding(16) // 舒适
.padding(20) // 宽松
// 内容边距
.contentMargins(16) // 统一边距
.contentMargins(.horizontal, 20) // 仅水平边距Safe Areas
安全区域
swift
// Respect toolbar safe area
.safeAreaInset(edge: .top) {
ToolbarContent()
}
// Ignore safe area for backgrounds
.ignoresSafeArea(.container, edges: .top)
// Content that should avoid toolbar
.safeAreaPadding(.top)swift
// 尊重工具栏安全区域
.safeAreaInset(edge: .top) {
ToolbarContent()
}
// 背景忽略安全区域
.ignoresSafeArea(.container, edges: .top)
// 内容避开工具栏
.safeAreaPadding(.top)Minimum Touch/Click Targets
最小点击/触控目标
swift
// Minimum 44x44 points for clickable elements
Button { } label: {
Image(systemName: "gear")
}
.frame(minWidth: 44, minHeight: 44)
// Use contentShape for larger hit areas
RoundedRectangle(cornerRadius: 8)
.frame(width: 200, height: 100)
.contentShape(Rectangle())
.onTapGesture { }swift
// 可点击元素最小44x44点
Button { } label: {
Image(systemName: "gear")
}
.frame(minWidth: 44, minHeight: 44)
// 扩大点击区域
RoundedRectangle(cornerRadius: 8)
.frame(width: 200, height: 100)
.contentShape(Rectangle())
.onTapGesture { }Adaptive Layouts
自适应布局
swift
// Responsive to window size
GeometryReader { geometry in
if geometry.size.width > 600 {
HStack { content }
} else {
VStack { content }
}
}
// Grid that adapts
LazyVGrid(columns: [
GridItem(.adaptive(minimum: 150, maximum: 250))
], spacing: 16) {
ForEach(items) { ItemView(item: $0) }
}swift
// 响应窗口尺寸
GeometryReader { geometry in
if geometry.size.width > 600 {
HStack { content }
} else {
VStack { content }
}
}
// 自适应网格
LazyVGrid(columns: [
GridItem(.adaptive(minimum: 150, maximum: 250))
], spacing: 16) {
ForEach(items) { ItemView(item: $0) }
}9. Accessibility
9. 无障碍访问
VoiceOver
VoiceOver
swift
// Labels and hints
Button { } label: {
Image(systemName: "plus")
}
.accessibilityLabel("Add item")
.accessibilityHint("Creates a new item in your library")
// Grouping related elements
VStack {
Text(item.title)
Text(item.subtitle)
}
.accessibilityElement(children: .combine)
// Custom actions
.accessibilityAction(named: "Delete") {
deleteItem()
}swift
// 标签与提示
Button { } label: {
Image(systemName: "plus")
}
.accessibilityLabel("添加项目")
.accessibilityHint("在你的库中创建一个新项目")
// 关联元素分组
VStack {
Text(item.title)
Text(item.subtitle)
}
.accessibilityElement(children: .combine)
// 自定义操作
.accessibilityAction(named: "删除") {
deleteItem()
}Keyboard Navigation
键盘导航
swift
// Focus management
@FocusState private var focusedField: Field?
TextField("Name", text: $name)
.focused($focusedField, equals: .name)
.onSubmit {
focusedField = .email
}
// Focusable custom views
.focusable()
.onMoveCommand { direction in
handleArrowKey(direction)
}swift
// 焦点管理
@FocusState private var focusedField: Field?
TextField("姓名", text: $name)
.focused($focusedField, equals: .name)
.onSubmit {
focusedField = .email
}
// 自定义视图可聚焦
.focusable()
.onMoveCommand { direction in
handleArrowKey(direction)
}Dynamic Type
动态字体
swift
// Scales with user preference
Text("Content")
.dynamicTypeSize(.large ... .accessibility3)
// Fixed size when necessary (use sparingly)
Text("Fixed")
.dynamicTypeSize(.large)swift
// 随用户偏好缩放
Text("内容")
.dynamicTypeSize(.large ... .accessibility3)
// 必要时固定尺寸(谨慎使用)
Text("固定尺寸")
.dynamicTypeSize(.large)Reduce Motion
减少动画
swift
@Environment(\.accessibilityReduceMotion) var reduceMotion
.animation(reduceMotion ? .none : .spring(), value: isExpanded)
// Alternative non-animated transitions
.transaction { transaction in
if reduceMotion {
transaction.animation = nil
}
}swift
@Environment(\.accessibilityReduceMotion) var reduceMotion
.animation(reduceMotion ? .none : .spring(), value: isExpanded)
// 替代非动画过渡
.transaction { transaction in
if reduceMotion {
transaction.animation = nil
}
}High Contrast
高对比度
swift
@Environment(\.colorSchemeContrast) var contrast
// Increase contrast when needed
.foregroundStyle(contrast == .increased ? .primary : .secondary)swift
@Environment(\.colorSchemeContrast) var contrast
// 必要时提高对比度
.foregroundStyle(contrast == .increased ? .primary : .secondary)10. Modern API Replacements
10. 现代API替代方案
Deprecated → Modern
已弃用 → 现代API
| Deprecated | Modern | Notes |
|---|---|---|
| | Split for macOS, Stack for simple flows |
| | Built-in column support |
| | Proper split view behavior |
| | Toolbar applies to correct scope |
| | Pure SwiftUI window management |
| | Declarative menus |
| | SwiftUI toolbar API |
| | SwiftUI Touch Bar |
| | SwiftUI file dialog |
| | SwiftUI save dialog |
| | Proper material support |
| Custom blur effects | | Native Liquid Glass |
| 已弃用API | 现代API | 说明 |
|---|---|---|
| | macOS用Split,简单流程用Stack |
| | 内置分栏支持 |
| | 标准分栏视图行为 |
详情页中的 | 在NavigationSplitView上使用 | 工具栏应用于正确范围 |
| | 纯SwiftUI窗口管理 |
| | 声明式菜单 |
| | SwiftUI工具栏API |
| | SwiftUI触控栏 |
| | SwiftUI文件对话框 |
| | SwiftUI保存对话框 |
用 | | 标准材质支持 |
| 自定义模糊效果 | | 原生Liquid Glass效果 |
AppKit Interop (When Needed)
AppKit互操作(必要时)
swift
// Wrap AppKit view
struct NSViewWrapper: NSViewRepresentable {
func makeNSView(context: Context) -> NSView {
// Create and configure NSView
}
func updateNSView(_ nsView: NSView, context: Context) {
// Update when SwiftUI state changes
}
}
// Access NSWindow
.background(WindowAccessor { window in
window?.titlebarAppearsTransparent = true
})swift
// 包装AppKit视图
struct NSViewWrapper: NSViewRepresentable {
func makeNSView(context: Context) -> NSView {
// 创建并配置NSView
}
func updateNSView(_ nsView: NSView, context: Context) {
// SwiftUI状态变化时更新
}
}
// 访问NSWindow
.background(WindowAccessor { window in
window?.titlebarAppearsTransparent = true
})11. Review Checklist
11. 审核检查清单
Liquid Glass & Materials
Liquid Glass与材质
- Sidebars use or appropriate material
.glassEffect() - Toolbars have translucent appearance
- Content areas remain clear (not overly translucent)
- Materials adapt properly to light/dark mode
- Fallback materials provided for pre-Tahoe
- 侧边栏使用 或合适的材质
.glassEffect() - 工具栏具备半透明外观
- 内容区域保持清晰(不过度半透明)
- 材质可正确适配明暗模式
- 为Tahoe之前的版本提供兼容材质
Navigation & Windows
导航与窗口
- used for multi-column layouts
NavigationSplitView - Sidebar has proper min/max width constraints
- Inspector panel available for detail/properties
- Window restoration configured
- Document-based apps use
DocumentGroup - Multiple window sizes tested
- 多栏布局使用
NavigationSplitView - 侧边栏设置了正确的最小/最大宽度限制
- 提供详情/属性检查器面板
- 配置了窗口状态恢复
- 文档类应用使用
DocumentGroup - 测试了多种窗口尺寸
Controls & Interaction
控件与交互
- Control sizes appropriate for context
- Primary actions use
.borderedProminent - Destructive actions properly marked with role
.destructive - Tables have context menus
- Popovers have appropriate sizing
- 控件尺寸符合上下文场景
- 主要操作使用
.borderedProminent - 破坏性操作正确标记 角色
.destructive - 表格具备上下文菜单
- 弹出框尺寸合适
Keyboard & Shortcuts
键盘与快捷键
- Standard shortcuts implemented (⌘N, ⌘S, ⌘W, etc.)
- Custom shortcuts don't conflict with system
- All interactive elements keyboard accessible
- Focus order logical
- Menu bar commands have shortcuts
- 实现了标准快捷键(⌘N、⌘S、⌘W等)
- 自定义快捷键不与系统冲突
- 所有交互元素支持键盘访问
- 焦点顺序符合逻辑
- 菜单栏命令配备快捷键
Accessibility
无障碍访问
- All images have accessibility labels
- Custom controls have proper roles
- VoiceOver tested
- Keyboard navigation complete
- Reduce Motion respected
- High Contrast mode tested
- 所有图片都有无障碍标签
- 自定义控件具备正确的角色
- 测试过VoiceOver
- 键盘导航完整
- 遵循减少动画的设置
- 测试过高对比度模式
Platform Conventions
平台惯例
- App uses system appearance (not custom chrome)
- Settings in Preferences window (not separate)
- File dialogs use system sheets
- Drag and drop supported where expected
- Services menu integration (if applicable)
- 应用使用系统外观(而非自定义边框)
- 设置项在偏好设置窗口中(而非独立窗口)
- 文件对话框使用系统表单页
- 预期场景支持拖放操作
- 集成了服务菜单(如适用)
Visual Polish
视觉优化
- 8-point grid alignment
- Consistent spacing throughout
- Semantic colors used (adapts to themes)
- Typography follows SF Pro guidelines
- Minimum 44pt touch targets
- 遵循8点网格对齐
- 全局间距一致
- 使用语义化颜色(适配主题)
- 排版遵循SF Pro指南
- 点击目标最小44pt
Quick Reference: Control Shapes by Size
快速参考:按尺寸划分的控件形状
┌─────────────────────────────────────────────────────┐
│ Mini/Small/Medium │ Large/XLarge │
│ ┌──────────────────┐ │ ╭──────────────────╮ │
│ │ Rounded Rect │ │ │ Capsule │ │
│ └──────────────────┘ │ ╰──────────────────╯ │
│ │ │
│ Compact layouts │ Hero actions │
│ Toolbars, sidebars │ Onboarding, CTAs │
└─────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────┐
│ Mini/Small/Medium │ Large/XLarge │
│ ┌──────────────────┐ │ ╭──────────────────╮ │
│ │ 圆角矩形 │ │ │ 胶囊形 │ │
│ └──────────────────┘ │ ╰──────────────────╯ │
│ │ │
│ 紧凑布局 │ 核心操作 │
│ 工具栏、侧边栏 │ 引导页、CTA按钮 │
└─────────────────────────────────────────────────────┘Quick Reference: Window Styles
快速参考:窗口样式
┌─────────────────────────────────────────────────────┐
│ .automatic Standard window with titlebar │
│ .hiddenTitleBar Full content, titlebar hidden │
│ .plain No chrome, utility panels │
│ .unified Toolbar merges with titlebar │
│ .unifiedCompact Compact unified toolbar │
└─────────────────────────────────────────────────────┘┌─────────────────────────────────────────────────────┐
│ .automatic 带标题栏的标准窗口 │
│ .hiddenTitleBar 内容全屏,标题栏隐藏 │
│ .plain 无边框,工具面板 │
│ .unified 工具栏与标题栏合并 │
│ .unifiedCompact 紧凑的合并式工具栏 │
└─────────────────────────────────────────────────────┘Quick Reference: Navigation Patterns
快速参考:导航模式
┌─────────────┬───────────────┬─────────────────────┐
│ Sidebar │ Content │ Detail │
│ │ │ │
│ Source │ List or │ Selected item │
│ List │ Grid │ properties │
│ │ │ │
│ Collections│ Items │ Inspector panel │
│ Folders │ Browse │ Edit view │
│ │ │ │
│ Min: 180 │ Flexible │ Min: 300 │
│ Max: 300 │ │ Ideal: 400+ │
└─────────────┴───────────────┴─────────────────────┘
NavigationSplitView (three-column)┌─────────────┬───────────────┬─────────────────────┐
│ 侧边栏 │ 内容栏 │ 详情栏 │
│ │ │ │
│ 源列表 │ 列表或网格 │ 选中项属性 │
│ │ │ │
│ 集合/文件夹 │ 项目浏览 │ 检查器面板/编辑视图│
│ │ │ │
│ 最小:180 │ 自适应 │ 最小:300 │
│ 最大:300 │ │ 理想:400+ │
└─────────────┴───────────────┴─────────────────────┘
NavigationSplitView(三栏布局)