Build an AppKit app with the new design
SwiftUI & UI Frameworks 进阶 1m

用新设计构建 AppKit 应用

Build an AppKit app with the new design

2025年6月9日

在 Apple 官方观看视频

一句话判断

macOS Tahoe 的 Liquid Glass 来了——AppKit 里 toolbar、sidebar、controls 全变了,好消息是大部分自动生效,坏消息是你得清理掉那些 VisualEffectView 和硬编码高度。

这场 Session 讲了什么

Session 从上到下讲了 macOS Tahoe 新设计系统在 AppKit 中的体现和适配 API。主要覆盖四个区域:App 结构(toolbar 玻璃材质、sidebar 浮动效果、窗口圆角与同心性)、Scroll Edge Effect(滚动内容与玻璃元素重叠时的视觉效果)、Controls(新尺寸、新形状、色彩浓度、玻璃按钮)、以及 Liquid Glass 自定义(NSGlassEffectViewNSGlassEffectContainerView)。

这不是一个设计理念 Session——它是实打实的 API 导览。哪些行为是自动的(toolbar 自动分组到玻璃上、sidebar 自动浮动),哪些需要你手动调整(移除旧的 VisualEffectView、设置 safe area、调整控制尺寸),都有明确的代码示例。

值得深挖的点

Toolbar 的自动分组与手动覆盖

AppKit 现在自动把 toolbar 元素按控件类型分组到玻璃材质上。独立按钮聚合到同一块玻璃,Segmented Control、PopUp Button、搜索控件各自独立。这个分组基于控件的类型自动判断。

想手动控制?用 NSToolbarItemGroup 强制分组,或插入 spacer 分隔。非交互元素(自定义标题、状态指示器)应该设 isBordered = false 移除玻璃背景——不然看起来像按钮。

玻璃支持着色:NSToolbarItem.style = .prominent 用强调色着色,backgroundTintColor 可以指定自定义颜色。Badge API(NSItemBadge)可以在工具栏项上显示未读计数。

sidebar 现在是浮动在内容上方的玻璃面板,inspector 是与内容并排的边缘到边缘玻璃。用 NSSplitViewController 的 sidebar/inspector behavior 自动获得正确效果。

关键变更:sidebar 上以前的 NSVisualEffectView 必须移除——它会挡住新的玻璃材质。设置 automaticallyAdjustsSafeAreaInsets = true 让内容延伸到 sidebar 下方,配合 safe area layout guide 定位。

NSBackgroundExtensionView 是全新的 API,解决内容延伸到 sidebar 下方但没有足够负空间的问题。它在 safe area 内显示真实内容,safe area 外用视觉效果(镜像 + 模糊)填充,看起来像内容无缝延伸但实际没有遮挡任何内容。

窗口圆角与 LayoutRegion API

新设计的窗口有更大的圆角(toolbar 窗口),圆角尺寸与 toolbar 高度成比例,实现同心性(concentricity)。但这会裁切靠近窗口边缘的内容。

新 API NSView.LayoutRegion 描述视图的布局区域(类似 safe area),支持角落回避。可以按水平或垂直方向 inset 来避开圆角。获取 layout guide 后直接用 Auto Layout 约束定位元素。

Controls 的四大变化

  1. 新尺寸 Extra Large:用于强调最重要的操作(媒体播放器的播放按钮、通讯 App 的拨号按钮)。Mini/Small/Medium 略微增高,Auto Layout 应对即可,不要硬编码高度。

  2. 新形状:Mini-Medium 保持圆角矩形(适合高密度布局),Large 和 Extra Large 变成胶囊形。borderShape 属性可以覆盖按钮、PopUp Button、Segmented Control 的形状。

  3. Tint Prominence:控制按钮色彩浓度的四个级别——automatic、none、secondary、primary。默认按钮自动为 primary,破坏性操作用 secondary + 红色。Slider 的 track 填充也由这个属性控制。

  4. Glass Bezel Style:按钮的新材质选项,用 Liquid Glass 替代标准背景,适合需要浮动在内容上的按钮。兼容现有的 bezelColor 做玻璃着色。

NSGlassEffectView 与分组

NSGlassEffectView 是把自定义内容放到玻璃上的核心 API。设置 contentView 后 AppKit 自动处理所有视觉效果(自适应外观、legibility 等)。

多个玻璃元素靠近时用 NSGlassEffectContainerView 分组。好处:玻璃可以流体式融合/分离(liquid effect),自适应外观在组内统一,渲染只需一次采样 pass(性能更好)。玻璃不能直接采样其他玻璃——不分组的话视觉结果不一致。

代码片段

1. 移除旧 VisualEffectView 并设置 safe area 延伸

场景:sidebar 内有旧的毛玻璃效果 View,需要清理。

// ❌ 移除:旧的 sidebar 背景材质
// sidebarView.addSubview(NSVisualEffectView()) // 删除这行

// ✅ 新的:让内容延伸到 sidebar 下方
contentSplitItemViewController.view.automaticallyAdjustsSafeAreaInsets = true
// 内容自动延伸,safe area guide 告诉你未被遮挡的区域

2. 用 LayoutRegion 避开窗口圆角

场景:按钮靠近窗口角落被圆角裁切。

override func updateConstraints() {
    let region = safeAreaLayoutGuide
        .layoutGuide(for: .safeArea, including: .horizontalCorners)
    NSLayoutConstraint.activate([
        newFolderButton.leadingAnchor.constraint(equalTo: region.leadingAnchor),
        newFolderButton.topAnchor.constraint(equalTo: region.topAnchor)
    ])
}

3. Glass Effect Container 分组

场景:统计数据面板和运动类型选择器作为一组玻璃元素。

let container = NSGlassEffectContainerView()
container.contentView = stackView // 统计 + 选择器在同一个 stack 中
container.spacing = 8 // 控制玻璃融合的间距

// 替换到现有布局
parentView.replaceSubview(oldStackView, with: container)

最佳实践

第一步:用 Xcode 26 构建。大部分新设计会自动生效——toolbar 浮动、sidebar 玻璃、控件新外观。这是最低成本的第一轮适配。

清理遗留代码:移除 sidebar 中的 NSVisualEffectView,移除硬编码的控件高度(改用 Auto Layout),给菜单项加 symbol icon。

内容延伸到边缘:充分利用浮动 toolbar 和 sidebar 的视觉效果,让内容(地图、照片、艺术品)延伸到这些区域下方。用 NSBackgroundExtensionView 处理没有足够负空间的艺术作品。

Liquid Glass 用在刀刃上:只给最高层级的控件(浮动工具、编辑控件)用玻璃材质。不要大面积使用——玻璃的折射和反射效果在大面积使用时会造成视觉混乱。用 NSGlassEffectContainerView 分组相邻的玻璃元素。

还有什么值得关注

  • Menu 的 symbol icon:新设计鼓励所有菜单项都有图标。Session “Get to know the new design system” 有详细的图标选择指南。
  • prefersCompactControlSizeMetrics:如果 App 有高密度布局(复杂 Inspector、Popover),设置这个属性让控件回到旧版 macOS 的尺寸,避免布局被撑开。
  • Slider 的 neutralValue:新 API,让滑块的填充色从任意位置开始而非仅从最小端。播放速度控制(1x 为中性值)是典型用例。
  • Liquid Glass 的自适应特性:玻璃材质会根据背后内容的亮度自动切换明暗外观,Dark Mode 的支持代码自动生效——你之前为 Dark Mode 做的适配现在也用于玻璃的自适应。
SwiftUI