WWDC Quick Look 💓 By SwiftGGTeam
What's new in SwiftUI

What's new in SwiftUI

观看原视频

Highlight

SwiftUI 在 WWDC 2022 中新增 Swift Charts、NavigationStack、NavigationSplitView、Layout 协议、Grid、ShareLink、PhotosPicker、Transferable 和多项控件更新,覆盖图表、导航、布局、分享和跨平台交互。

核心内容

SwiftUI 早期常见的麻烦,是简单界面很快,复杂应用会碰到几类缺口:图表要找第三方库,导航状态难以持久化,自定义布局依赖 GeometryReader,分享、拖拽、照片选择需要跨框架拼接。

2022 年的 SwiftUI 更新集中补这些缺口。Apple 用声明式 API 把图表、导航、布局、分享和数据传输放进同一套模型。开发者写的仍然是 view 和 modifier,但覆盖的应用结构更完整。

本场演讲用一个 Party Planner 示例串起更新:用 Swift Charts 展示待办进度,用新的导航 API 组织层级,用 Grid 和 Layout 处理自定义排布,用 PhotosPicker、ShareLink 和 Transferable 处理照片、分享和拖拽。

详细内容

Swift Charts

02:51)Swift Charts 用 Chart 容器和 mark 类型描述图表。BarMarkLineMarkRuleMark 等 mark 与 SwiftUI modifier 配合,系统处理本地化、Dynamic Type、Dark Mode 和可访问性。

Chart(tasks) { task in
    BarMark(
        x: .value("Task", task.name),
        y: .value("Remaining", task.remainingCount)
    )
    .foregroundStyle(by: .value("Category", task.category))
}

关键点

  • Chart(tasks) 遍历模型集合生成图表
  • BarMark 声明柱状图的单个 mark
  • xy 使用 .value 绑定语义标签和数据
  • foregroundStyle(by:) 按类别自动生成颜色编码

数据驱动导航

10:27NavigationStack 替代传统 stack 导航。开发者用 value-based NavigationLink 表示目的地,用 navigationDestination 注册值到视图的映射。导航路径可以保存在数组中,适合恢复状态或一键回到根页面。

NavigationStack(path: $path) {
    List(tasks) { task in
        NavigationLink(value: task) {
            Text(task.name)
        }
    }
    .navigationDestination(for: PartyTask.self) { task in
        TaskDetail(task: task)
    }
}

关键点

  • path 保存当前导航栈状态
  • NavigationLink(value:) 传递模型值,不直接构造目标视图
  • navigationDestination 统一定义某类值对应的页面
  • 修改 path 数组即可控制 push、pop 和恢复

自定义布局

22:02Layout 协议让自定义布局成为 SwiftUI 的一等能力。过去常用 GeometryReader 手动测量,现在布局可以实现测量和摆放逻辑,并保留动画能力。

struct RadialLayout: Layout {
    func sizeThatFits(proposal: ProposedViewSize,
                      subviews: Subviews,
                      cache: inout ()) -> CGSize {
        proposal.replacingUnspecifiedDimensions()
    }

    func placeSubviews(in bounds: CGRect,
                       proposal: ProposedViewSize,
                       subviews: Subviews,
                       cache: inout ()) {
        for (index, subview) in subviews.enumerated() {
            let angle = Angle.degrees(Double(index) / Double(subviews.count) * 360)
            let point = CGPoint(x: bounds.midX + cos(angle.radians) * 120,
                                y: bounds.midY + sin(angle.radians) * 120)
            subview.place(at: point, anchor: .center, proposal: .unspecified)
        }
    }
}

关键点

  • Layout 分离测量和摆放
  • sizeThatFits 返回容器需要的尺寸
  • placeSubviews 决定每个子视图的位置
  • subview.place 由布局系统执行最终摆放

分享与传输

24:45PhotosPicker 提供 SwiftUI 原生照片选择器。用户选择图片后,示例代码通过 loadTransferable(type: Image.self)PhotosPickerItem 加载为 SwiftUI Image

@Published var imageSelection: PhotosPickerItem? = nil {
    didSet {
        if let imageSelection = imageSelection {
            let progress = loadTransferable(from: imageSelection)
            imageState = .loading(progress)
        } else {
            imageState = .empty
        }
    }
}

private func loadTransferable(from imageSelection: PhotosPickerItem) -> Progress {
    return imageSelection.loadTransferable(type: Image.self) { result in
        DispatchQueue.main.async {
            guard imageSelection == self.imageSelection else { return }
            switch result {
            case .success(let image?):
                self.imageState = .success(image)
            case .success(nil):
                self.imageState = .empty
            case .failure(let error):
                self.imageState = .failure(error)
            }
        }
    }
}

关键点

  • imageSelection 保存用户在 PhotosPicker 中选择的 PhotosPickerItem
  • didSet 在选择变化时启动加载,并先把状态切到 .loading(progress)
  • loadTransferable(type: Image.self) 使用系统传输机制把选择项加载为 Image
  • guard imageSelection == self.imageSelection 避免旧的异步结果覆盖新的选择
  • successnilfailure 分支分别更新成功、空状态和错误状态

25:51)处理后的图片可以直接交给 ShareLink 分享。演讲还展示了 .dropDestination(payloadType: Image.self),同一类 Image 数据可用于拖拽接收。

if let item = viewModel.processedImage {
    ShareLink(
        item: item, preview: SharePreview("Birthday Effects"))
}

关键点

  • processedImage 存在时才显示分享入口
  • ShareLink 接收要分享的 item
  • SharePreview 设置系统分享面板中的预览标题
  • 这里使用 session 代码中的 Image,不扩展示例中没有出现的自定义 Transferable 实现

核心启发

  • 把运营看板改成原生 Swift Charts:用 ChartBarMarkLineMark 展示销售、习惯打卡或项目进度。系统自动处理无障碍和主题适配,适合替换轻量第三方图表库。

  • 让导航状态可保存:用 NavigationStack(path:) 管理详情页路径。用户重启应用后恢复到上次打开的项目详情,或在深链中直接构造路径进入多级页面。

  • 用 Layout 做品牌化排版:为照片墙、仪表盘、课程进度做自定义布局。实现 Layout 后,布局可以参与 SwiftUI 动画,不需要 GeometryReader 拼坐标。

  • 用 Transferable 统一分享和拖拽:让卡片、图片、笔记条目实现 Transferable。同一份数据模型同时支持 ShareLink、拖拽到其他 App、复制粘贴。

关联 Session

评论

GitHub Issues · utterances