SwiftUI 新特性总览
What's new in SwiftUI
2020年6月22日
一句话判断
SwiftUI 在 2020 年补齐了几乎所有关键短板——App 生命周期、Lazy 容器、列表/网格、侧边栏、Widget——从”可以尝鲜”正式进入了”可以用于生产”的阶段。
这场 Session 讲了什么
这是 SwiftUI 年度更新总览,覆盖了 iOS 14 中所有新增和改进的功能。
最重磅的更新:App 协议(纯 SwiftUI App 入口,不再需要 AppDelegate)、LazyVStack/LazyHStack/LazyVGrid/LazyVGrid(高性能列表和网格)、ScrollView 的改进(支持 Lazy 子视图)、List 的新 API(支持大纲视图、可折叠分组)。
UI 组件方面:新增了 ProgressView(进度条/加载指示器)、Link(可点击链接)、Label(图标+文字的组合)、Menu(上下文菜单)、Picker 的新样式(如分段控件样式)、以及 SideBar 列表样式。
应用生态方面:SwiftUI 现在支持 WatchOS App、WidgetKit、macOS 的新控件(如 ToolbarItem)、以及多平台 App 的统一代码结构。
值得深挖的点
从 2019 到 2020 的跨越。 2019 年的 SwiftUI 缺少太多关键功能:没有懒加载容器(长列表直接崩溃)、没有 App 生命周期管理、列表功能极其有限。2020 年的更新几乎填满了这些空白。如果你在 2019 年评估过 SwiftUI 并放弃了,现在是重新评估的时候。
Lazy 容器的引入改变了 SwiftUI 的可用性边界。 没有 Lazy 容器时,SwiftUI 只适合展示少量数据(几十个元素以内)。LazyVStack/LazyHStack 引入后,SwiftUI 可以处理成百上千条数据,终于覆盖了 UIKit 中 UITableView/UICollectionView 的核心场景。
代码片段
// 新的 App 入口
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
// Label——图标+文字的标准组合
Label("设置", systemImage: "gearshape")
.font(.headline)
// ProgressView——加载指示器
ProgressView("加载中...")
.progressViewStyle(CircularProgressViewStyle())
// Menu——上下文菜单
Menu {
Button("复制", action: copyText)
Button("粘贴", action: pasteText)
Divider()
Button("删除", role: .destructive, action: deleteItem)
} label: {
Image(systemName: "ellipsis.circle")
}
// LazyVGrid——自适应网格
let columns = [GridItem(.adaptive(minimum: 150))]
ScrollView {
LazyVGrid(columns: columns, spacing: 16) {
ForEach(items) { item in
ItemCard(item: item)
}
}
.padding()
}
// 大纲视图
List(data, children: \.children) { item in
Label(item.name, systemImage: item.icon)
}
.listStyle(SidebarListStyle())
// 新的 Toolbar API
NavigationView {
List(messages) { message in
MessageRow(message: message)
}
.navigationTitle("收件箱")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
ToolbarItem(placement: .bottomBar) {
Button(action: compose) {
Image(systemName: "square.and.pencil")
}
}
}
}
// .navigationTitle 替代了 NavigationBar 的 title 配置
// .toolbar 替代了 toolbarItems delegate 方法
最佳实践
- 新项目直接用 SwiftUI。 2020 年的 SwiftUI 已经足够完整,可以支撑大多数类型的 App。
- 现有 UIKit 项目逐步引入 SwiftUI。 用
UIHostingController将 SwiftUI 视图嵌入 UIKit,从新功能开始尝试。 - 优先使用 Lazy 容器处理列表数据。 几乎所有展示列表数据的场景都应该用 Lazy 版本。
- 用 App 协议替代 AppDelegate。 新项目的启动代码更简洁,老项目可以用
@UIApplicationDelegateAdaptor桥接。
还有什么值得关注
- SwiftUI 新增了对 watchOS App 的完整支持(包括独立的 watchOS App)
- macOS 上新增了 ToolbarItem、Table 等桌面端专用控件
- Text 组件支持 Markdown 解析(通过
AttributedString) matchedGeometryEffect可以在视图切换时创建共享元素的过渡动画