What's new in SwiftUI
Swift & UI 入门 32m

SwiftUI 新特性总览

What's new in SwiftUI

2020年6月22日

在 Apple 官方观看视频

一句话判断

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 可以在视图切换时创建共享元素的过渡动画
WWDC 2020