macos-hig-designer

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

macOS 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

三大核心准则

PrincipleDescriptionImplementation
HierarchyVisual layers through Liquid Glass translucencyUse
.glassEffect()
, materials, and depth
HarmonyConcentric alignment between hardware/softwareRound corners, consistent radii, flowing shapes
ConsistencyPlatform conventions that adapt to contextFollow standard patterns, respect user preferences
设计原则说明实现方式
层级结构通过Liquid Glass半透明效果实现视觉层级使用
.glassEffect()
、材质和深度效果
和谐统一硬件与软件之间的同心对齐圆角、统一半径、流畅形状
一致性适配上下文的平台惯例遵循标准模式,尊重用户偏好

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

窗口样式

StyleUse Case
.automatic
Standard app windows
.hiddenTitleBar
Content-focused (media players)
.plain
Utility windows, panels
.unified
Integrated toolbar appearance
.unifiedCompact
Compact toolbar height
样式适用场景
.automatic
标准应用窗口
.hiddenTitleBar
内容优先型(媒体播放器)
.plain
工具窗口、面板
.unified
集成式工具栏外观
.unifiedCompact
紧凑工具栏高度

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, .automatic
swift
.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、.automatic

Custom 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 dropdown
swift
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:
ActionShortcutImplementation
New⌘N
.keyboardShortcut("n")
Open⌘O
.keyboardShortcut("o")
Save⌘S
.keyboardShortcut("s")
Close⌘W
.keyboardShortcut("w")
Undo⌘Z
.keyboardShortcut("z")
Redo⇧⌘Z
.keyboardShortcut("z", modifiers: [.command, .shift])
Cut⌘X
.keyboardShortcut("x")
Copy⌘C
.keyboardShortcut("c")
Paste⌘V
.keyboardShortcut("v")
Select All⌘A
.keyboardShortcut("a")
Find⌘F
.keyboardShortcut("f")
Preferences⌘,
.keyboardShortcut(",")
Hide⌘HSystem handled
Quit⌘QSystem handled
适用时请务必实现以下快捷键:
操作快捷键实现方式
新建⌘N
.keyboardShortcut("n")
打开⌘O
.keyboardShortcut("o")
保存⌘S
.keyboardShortcut("s")
关闭⌘W
.keyboardShortcut("w")
撤销⌘Z
.keyboardShortcut("z")
重做⇧⌘Z
.keyboardShortcut("z", modifiers: [.command, .shift])
剪切⌘X
.keyboardShortcut("x")
复制⌘C
.keyboardShortcut("c")
粘贴⌘V
.keyboardShortcut("v")
全选⌘A
.keyboardShortcut("a")
查找⌘F
.keyboardShortcut("f")
偏好设置⌘,
.keyboardShortcut(",")
隐藏⌘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

控件尺寸

SizeShapeUse Case
MiniRounded rectCompact toolbars, dense UIs
SmallRounded rectSecondary controls, sidebars
RegularRounded rectPrimary controls (default)
LargeCapsuleProminent actions
Extra LargeCapsule + GlassHero 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 blue
swift
// 前景色
.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 only
swift
// 标准间距值
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

DeprecatedModernNotes
NavigationView
NavigationSplitView
/
NavigationStack
Split for macOS, Stack for simple flows
.navigationViewStyle(.columns)
NavigationSplitView
Built-in column support
List { }.listStyle(.sidebar)
with
NavigationLink
NavigationSplitView
sidebar
Proper split view behavior
.toolbar { ToolbarItem(...) }
in detail
.toolbar
on NavigationSplitView
Toolbar applies to correct scope
NSWindowController
WindowGroup
/
Window
Pure SwiftUI window management
NSMenu
/
NSMenuItem
.commands { }
/
CommandMenu
Declarative menus
NSToolbar
.toolbar { }
SwiftUI toolbar API
NSTouchBar
.touchBar { }
SwiftUI Touch Bar
NSOpenPanel.begin()
.fileImporter()
SwiftUI file dialog
NSSavePanel.begin()
.fileExporter()
SwiftUI save dialog
.background(Color.clear)
for materials
.background(.regularMaterial)
Proper material support
Custom blur effects
.glassEffect()
(Tahoe)
Native Liquid Glass
已弃用API现代API说明
NavigationView
NavigationSplitView
/
NavigationStack
macOS用Split,简单流程用Stack
.navigationViewStyle(.columns)
NavigationSplitView
内置分栏支持
List { }.listStyle(.sidebar)
搭配
NavigationLink
NavigationSplitView
侧边栏
标准分栏视图行为
详情页中的
.toolbar { ToolbarItem(...) }
在NavigationSplitView上使用
.toolbar
工具栏应用于正确范围
NSWindowController
WindowGroup
/
Window
纯SwiftUI窗口管理
NSMenu
/
NSMenuItem
.commands { }
/
CommandMenu
声明式菜单
NSToolbar
.toolbar { }
SwiftUI工具栏API
NSTouchBar
.touchBar { }
SwiftUI触控栏
NSOpenPanel.begin()
.fileImporter()
SwiftUI文件对话框
NSSavePanel.begin()
.fileExporter()
SwiftUI保存对话框
.background(Color.clear)
实现材质效果
.background(.regularMaterial)
标准材质支持
自定义模糊效果
.glassEffect()
(Tahoe)
原生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
    .glassEffect()
    or appropriate material
  • 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

导航与窗口

  • NavigationSplitView
    used for multi-column layouts
  • 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
    .destructive
    role
  • 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(三栏布局)