Highlight
TabView 新增 type-safe 语法和
.sidebarAdaptable样式,一份代码即可在 tab bar 与 sidebar 之间切换,用户还能自由排序和隐藏标签页。
核心内容
iPad 上的 sidebar 应用一直有个尴尬的问题:sidebar 在内容多时好用,但屏幕空间有限时 tab bar 更紧凑。之前开发者只能用 NavigationSplitView 模拟这种切换,代码复杂且行为不一致。iOS 18 给 TabView 加了 .sidebarAdaptable 样式,一行修饰符就能让用户在 tab bar 和 sidebar 之间自由切换,系统还自带标签页排序和隐藏的定制功能。
SwiftUI 这次更新覆盖了四个板块。第一,让 App 焕然一新:TabView 的新语法、Mesh Gradient、Swift Charts 函数绘图、动态 Table 列、Control Widgets。第二,平台适配:macOS 窗口样式定制(plain style、floating level、默认位置)、visionOS 的 pushWindow 和自定义 hover effect、Apple Pencil Pro 的 squeeze 手势。第三,框架基础:自定义容器(subviewOf)、@Entry 宏、文本选择 API、onScrollGeometryChange、Swift 6 兼容性、UIKit/AppKit 动画桥接。第四,沉浸体验:volume baseplate 可见性控制、沉浸空间允许级别、passthrough 视频效果、自定义 TextRenderer。
详细内容
TabView 新语法
TabView 有了 type-safe 的 Tab 构造器,替代了旧的字符串 tabItem。每个 Tab 可以加 customizationID,配合 TabViewCustomization 状态保存用户的排序和隐藏偏好(01:38)。
TabView {
Tab("Parties", image: "party.popper") {
PartiesView(parties: Party.all)
}
.customizationID("karaoke.tab.parties")
Tab("Planning", image: "pencil.and.list.clipboard") {
PlanningView()
}
.customizationID("karaoke.tab.planning")
}
.tabViewStyle(.sidebarAdaptable)
.tabViewCustomization($customization)
关键点:
Tab("Parties", image:...)替代.tabItem { Label(...) },编译期就能发现标签配置错误.sidebarAdaptable让用户在 tab bar 和 sidebar 之间一键切换$customization绑定保存了用户的定制状态,下次打开自动恢复
Sheet 统一尺寸 + Zoom 过渡
Sheet 弹窗的尺寸终于有了跨平台统一方案。.presentationSizing(.form) 生成紧凑表单,.page 生成全页(02:28)。导航过渡新增 .zoom 效果,配合 matchedTransitionSource 和 @Namespace 实现元素缩放转场(02:39)。
Control Widgets
新增 ControlWidget 协议,只需几行代码就能创建出现在控制中心或锁屏的按钮或开关,甚至可以绑定到 Action Button(03:18)。
struct StartPartyControl: ControlWidget {
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(kind: "com.apple.karaoke_start_party") {
ControlWidgetButton(action: StartPartyIntent()) {
Label("Start the Party!", systemImage: "music.mic")
Text(PartyManager.shared.nextParty.name)
}
}
}
}
关键点:
ControlWidgetButton的 action 接收AppIntent,和 Shortcuts/App Intents 体系打通- 控件可以显示动态内容(如下一场派对名称)
Swift Charts 函数绘图 + 动态 Table 列
LinePlot 可以直接绘制数学函数(03:49)。TableColumnForEach 让列数可以动态生成(04:18)。
Mesh Gradient
通过在网格点之间插值颜色,创建丰富的渐变效果(04:42)。
MeshGradient(
width: 3,
height: 3,
points: [
.init(0, 0), .init(0.5, 0), .init(1, 0),
.init(0, 0.5), .init(0.3, 0.5), .init(1, 0.5),
.init(0, 1), .init(0.5, 1), .init(1, 1)
],
colors: [
.red, .purple, .indigo,
.orange, .cyan, .blue,
.yellow, .green, .mint
]
)
关键点:
points数组定义网格坐标(0~1 范围),可以偏移以制造不对称渐变colors数组与 points 一一对应,系统自动插值
macOS 窗口定制
Window scene 支持 .windowStyle(.plain) 去掉默认窗口装饰、.windowLevel(.floating) 置顶、defaultWindowPlacement 控制初始位置(07:04)。WindowDragGesture 让无标题栏窗口也能拖动(07:30)。
visionOS:pushWindow + Hover Effect
pushWindow 环境动作可以打开一个窗口同时隐藏来源窗口,适合聚焦式工作流(08:18)。新的闭包式 hoverEffect 可以精确控制 hover 状态下的缩放等视觉反馈(08:47)。
@Entry 宏 + 自定义容器
@Entry 宏一行代码替代整个 EnvironmentKey 协议实现,适用于 EnvironmentValues、FocusValues、Transaction、ContainerValues(13:52)。ForEach(subviewOf:) 可以遍历子视图,构建自定义容器(13:13)。
extension EnvironmentValues {
@Entry var karaokePartyColor: Color = .purple
}
文本选择 + 搜索焦点 + 文本建议
TextField 新增 selection 绑定,可以读写选区(15:06)。.searchFocused 绑定控制搜索框焦点(15:29)。.textInputSuggestions 给任意文本框添加自动补全(15:41)。
ScrollView 新 API
onScrollGeometryChange 高效响应滚动偏移变化(16:23),onScrollVisibilityChange 检测视图因滚动进入或离开屏幕(16:42),ScrollPosition.scrollTo(edge:) 程序化滚到边缘(16:54)。
UIKit/AppKit 动画桥接
UIView.animate(animation:) 和 NSAnimationContext.animate(animation:) 让 UIKit/AppKit 的属性变更用 SwiftUI 弹簧动画驱动,手势驱动的动画自动保留速度(18:34)。
visionOS 沉浸空间控制
volume 支持 .volumeBaseplateVisibility 控制底板显示(19:59),.onVolumeViewpointChange 响应观察角度变化(20:15)。沉浸空间的 ImmersionStyle.progressive 现在可以限定最小和初始沉浸比例(20:38),.preferredSurroundingsEffect(.colorMultiply(.purple)) 给 passthrough 视频叠加颜色滤镜(21:00)。
自定义 TextRenderer
TextRenderer 协议让你在 Text 视图上叠加自定义绘制,比如模糊发光效果(21:33)。
struct KaraokeRenderer: TextRenderer {
func draw(layout: Text.Layout, in context: inout GraphicsContext) {
for line in layout {
for run in line {
var glow = context
glow.addFilter(.blur(radius: 8))
glow.addFilter(purpleColorFilter)
glow.draw(run)
context.draw(run)
}
}
}
}
Text("A Whole View World")
.textRenderer(KaraokeRenderer())
关键点:
- 遍历
Text.Layout的 line 和 run,可以对每个片段单独绘制 - 先画一层模糊的副本作为发光底,再画原始文字,制造发光效果
核心启发
-
给 iPad App 加 sidebar/tab 切换:已有
NavigationSplitView模拟 sidebar 的项目,迁移到.sidebarAdaptableTabView 后代码更少、行为和系统一致,用户还能自定义标签页。怎么开始:把NavigationSplitView替换为TabView + Tab + .sidebarAdaptable,给每个 Tab 加customizationID。 -
用 Control Widget 把高频操作放到锁屏/控制中心:用户不需要打开 App 就能触发核心功能(开始记录、切换状态、快捷拍照),和 App Intents 打通后还能被 Shortcuts 调用。怎么开始:创建
ControlWidget实现,定义ControlWidgetButton或ControlWidgetToggle,绑定AppIntent。 -
用
onScrollVisibilityChange做懒加载视频播放:列表中的视频进入视口自动播放、离开视口自动暂停,省电且体验流畅。怎么开始:在VideoPlayer上加.onScrollVisibilityChange(threshold: 0.2)回调控制 play/pause。 -
用
UIView.animate(animation:)统一 UIKit 和 SwiftUI 动画:混编项目中 UIKit 部分的属性动画现在可以用 SwiftUI 弹簧曲线驱动,手势驱动的动画自动保留惯性速度,不再需要手动计算 timing curve。怎么开始:在UIView.animate(SwiftUI.Animation.spring(duration: 0.8))闭包中修改 UIKit 属性。
关联 Session
- Improve your tab and sidebar experience on iPad — 深入讲解 TabView 新语法和 sidebarAdaptable 的适配细节
- Enhance your UI animations and transitions — zoom 过渡、SwiftUI/UIKit 动画桥接的完整指南
- Demystify SwiftUI Containers — subviewOf、自定义容器和 ContainerValues 的原理与实践
- Dive deep into volumes and immersive spaces — volume 底板、视点变化、沉浸级别控制的详细用法
- Create custom visual effects with SwiftUI — TextRenderer 和自定义视觉效果的开发教程
评论
GitHub Issues · utterances