What's new in SwiftUI
SwiftUI 进阶 40m

SwiftUI 新特性

What's new in SwiftUI

2025年6月9日

在 Apple 官方观看视频

一句话判断

SwiftUI 这次最值得关注的不是 Liquid Glass 的视觉变化,而是 TextEditor 终于支持了 AttributedString——用纯 SwiftUI 构建富文本编辑器第一次成为现实。

这场 Session 讲了什么

SwiftUI 这次更新覆盖面很广,但如果你只记一件事,记住这个:过去五年里,任何需要富文本编辑的 SwiftUI 应用都不得不桥接 UITextView,写一堆 UIViewRepresentable 样板代码。现在 TextEditor 原生支持 AttributedString、选区管理和查找导航,这条桥接层终于可以拆了。

Liquid Glass 是另一个大变化,但对大多数开发者来说,它的影响是被动的——你不需要主动做什么,系统控件会自动采用新外观。真正需要你动手的是:检查你过去为 TabBar、Toolbar 写的自定义背景和模糊效果,它们大概率会和 Liquid Glass 冲突。glassEffect() 修饰符和 .glass 按钮样式是给那些需要自定义玻璃效果的人准备的。

其他值得注意的:@Animatable 宏消灭了手动实现 Animatable 协议的样板代码,visionOS 的 manipulable() 手势让 3D 交互不再是少数人的专属。

值得深挖的点

TextEditor 的富文本支持:为什么等了这么久

SwiftUI 从 2019 年发布至今,TextEditor 一直是纯文本工具。这不是 Apple 忘了——富文本编辑是一个极其复杂的问题域。选区管理、撤销栈、输入法交互、格式继承、大文档性能……每一个都是坑。Apple 选择在这个时间点放出原生支持,说明他们终于认为这些问题的解决方案成熟了。

新的 API 设计值得细看。AttributedTextSelection 不只是暴露选区范围,它把选区状态变成了 SwiftUI 的一等公民——你可以用 @State 管理它,这意味着选区变化天然遵循 SwiftUI 的声明式范式。AttributedTextFormattingDefinition 允许你定义”在代码块里自动用等宽字体,在引用块里自动用斜体”这类上下文敏感的格式规则。FindContext 把查找导航器内置到了编辑器里。

和旧方案对比:用 UITextView 包装时,你需要处理 updateUIView 的生命周期、协调 SwiftUI 状态和 UIKit 命令式 API、处理键盘避免逻辑……现在这些都不需要了。但有一个 trade-off:新 API 的灵活性可能不如直接操作 UITextView——如果你需要高度定制的文本布局或非标准输入法交互,UIKit 桥接可能仍然是唯一选择。

@Animatable 宏:编译器替你写代码

手动实现 Animatable 协议的痛点不是难度,是繁琐。每个可动画属性都需要写 animatableData 的 getter/setter,多个属性需要打包成 AnimatablePair,类型转换需要手动处理。@Animatable 宏用编译器魔法取代了这一切。

这不仅仅是语法糖。它降低了自定义动画的认知门槛——过去你需要理解 VectorArithmetic 协议才能做自定义过渡,现在只需要在结构体上加一个宏。但要注意:@Animatable 只适用于你的自定义 View 类型中的存储属性,系统类型(如 CGFloatColor)本身已经支持动画,不需要也不能用这个宏。

代码片段

Liquid Glass 效果:让自定义视图融入系统新设计语言。

struct GlassCard: View {
    var body: some View {
        VStack {
            Text("Hello, Liquid Glass")
                .font(.title)
            Button("Tap Me") { }
                .buttonStyle(.glass)
        }
        .padding()
        .glassEffect(.regular.interactive, in: .rect(cornerRadius: 20))
    }
}
// 坑:glassEffect 的 shape 参数决定裁剪边界,
// 圆角半径不对会导致边缘出现不自然的硬切

@Animatable 宏:一行代码替代过去 20 行的 Animatable 协议实现。

@Animatable
struct PulseRing: View {
    var scale: CGFloat  // 自动获得动画能力

    var body: some View {
        Circle()
            .stroke(.blue, lineWidth: 3)
            .scaleEffect(scale)
    }
}
// 坑:如果属性类型不支持 VectorArithmetic,编译器会报错,
// 但错误信息不一定能直接告诉你哪个属性有问题

富文本编辑器:纯 SwiftUI 实现,不再需要 UITextView 桥接。

struct RichTextEditor: View {
    @State private var text = AttributedString("开始编辑...")
    @State private var findContext = FindContext()
    @State private var selection = AttributedTextSelection()

    var body: some View {
        TextEditor(text: $text, selection: $selection)
            .findNavigator(isPresented: .constant(true), context: findContext)
            .attributedTextFormattingDefinition(.inline)
    }
}
// 坑:超长文档(>10000 字)的性能还需要实际验证,
// AttributedString 的 Copy-on-Write 在频繁编辑时可能产生意外的内存拷贝

最佳实践

已有项目:不要急着迁移。Liquid Glass 对系统控件是自动生效的,先编译看效果。如果过去给 TabBar、Toolbar 设置了自定义背景色或模糊效果,准备好花半天时间清理——它们大概率会和 Liquid Glass 冲突。TextEditor 的富文本支持值得评估,但现有的 UITextView 包装运行良好的话,没有理由立刻重写。

新项目:直接用新 APITextEditor + AttributedStringUITextView 包装简单一个数量级。@Animatable 宏在任何需要自定义动画的场景下都值得用。

visionOS 开发者:manipulable() 手势是真正的生产力提升,但要注意和系统手势(捏合、旋转)的冲突。

还有什么值得关注

  • WebView + WebPage 组合替代了 WKWebView 包装方案,app 内嵌网页的场景值得看看
  • scrollEdgeEffectStyle() 为滚动视图带来边缘视觉效果,和 Liquid Glass 配合效果很好
  • ToolbarSpacer 解决了玻璃工具栏项之间的视觉间距问题
SwiftUI Liquid Glass 动画 文本编辑 visionOS