大多数浏览器和
Developer App 均支持流媒体播放。
-
在 SwiftUI 内构建基于文档的 app
了解如何完全用 SwiftUI 创建一个基于文档的 app!我们将向你介绍 DocumentGroup API,以及它如何与你的 App 和 Scenes 组合在一起,使你可以添加现成的文档管理支持——例如文档浏览和标准命令——不需繁琐的工作。你将学习如何设置 Universal Type Identifiers,并了解是什么构成了基于文档的顶级 app。 为了充分利用本节内容,你首先需要熟悉在 SwiftUI 中构建 app。 请查阅“ SwiftUI 中 App 必备知识”了解更多信息。
资源
相关视频
WWDC23
WWDC20
-
下载
(大家好 WWDC 2020) 大家好 欢迎来到 WWDC (在 SwiftUI 内构建基于文档的 app) 大家好 我叫 Tina 我是 SwiftUI 工程师 今天我要谈谈如何在 SwiftUI 内 构建支持文档的 app (Tina SwiftUI 工程师) 第一个问题 什么是文档? 人们一直通过访达和文件 app 在macOS、iPadOS、iOS 上管理文档 他们可以按自己所需使用一些功能 诸如标签、云文件提供者 以及外部存储设备来组织项目 他们应该能使用 app 来无缝原地打开、查看并编辑文件 也包括更改原文档 所有支持原地打开文件的 app 中 都能看见这个更改 与此相反 对于有些 app 要先从数据库里导入文件 然后 app 才能管理它们 当你编辑导入的文档时 你其实在编辑原文档的副本 原文档未改变 一些专门 app 比如 Pixelmator 不仅允许用户管理原地打开的文件 还带给用户强大的编辑功能 包括同时打开多个文件 几乎所有这些 app 的核心 比如 Pixelmator Keynote 讲演和 Final Cut Pro 都允许用户这么管理文档 我们通常称呼它们为“基于文档的 app” 表明它们的软件行为 但你的 app 可以支持打开文档这一功能 而不用完全“基于文档” 像 Xcode 这样的 app 除了支持文档 还有额外的 UI 和功能 而邮件、控制台这样的 app 基本呈现出“非基于文档”的外观 但也支持打开额外文档 比如 EML 文件或崩溃报告
一个 SwiftUI 应用程序是由 app 场景和视图组成的 想添加文档支持 要使用另一个场景类型 叫做 DocumentGroup 如屏幕所示 它是一个简单的文本编辑 app 当你在 app 中使用 DocumentGroup 时 你在声明你的 app 支持 原地打开和管理这种类型的文档
正如视频“SwiftUI 的 app 概要”提到 我们的代码结构匹配 app 的所有权格层次结构 在这里 我们的 app 包含一个 DocumentGroup 场景 能打开多个此类文档窗口 当然作为组成元素 它可以支持 多种不同类型的 DocumentGroup 或者同时支持 WindowGroup 和 DocumentGroup 你可以把这些场景组合到你的 app 中 而 SwiftUI 会自动赋予你的 app 在那些场景下该有的平台行为 这包括 文档 app 特有的标准 UI 元素 Mac 上的状态追踪和接力功能 iOS 上带有搜索框和共享功能的 文档浏览器和导航栏 以上这些都可以通过极少代码实现 现在我们用 DocumentGroup 构建东西 我在我的 iPad Playground 上 用 SwiftUI 构建一个绘图 app 我在画布上可以添加不同颜色的图形 并改变它们的形状 我觉得这个程序挺好 我想把它建成一个 app 这样我能保存并管理我的绘图 我们看看如何实现 打开 Xcode 创建一个基于文档的 app 我希望它在 macOS 和 iOS 上都能运行 所以我选择多平台模板
我给它命名为“ShapeEdit”
里面已经带有模板了 我们来构建并运行它
我们现在有了一个文本编辑 app 它有之前我们提到的 一切文档支持功能 在继续深入之前 我们先看一下项目设置
我关注的是 macOS 目标 但我们要用的配置 同时适用于 iOS 和 macOS 目标
咱们看一下 Info.plist
Xcode 为“基于文档的 app” 添加了“文档类型”区域
标示符字段的值是通用类标示符 系统使用这个标示符 来把文件和你的 app 联系在一起 所以当它看到这种类型的文档时 它知道要在你的 app 中打开它 这个标示符在下面被声明成一个导入类
它是导入的 因为另一个方声明了这个纯文本类 我们导入这个类声明 来告诉系统这个 app 知道它 对我们的 app 来说 我们要声明一个自己的类 我们再回到这儿
创建一个
既然这个类是我们发明的 我们就需要导出这个类声明 来告诉系统我们是这个类的权威所有者 我们填写 “导出类标示符”区的信息来实现它
咱们给它一个描述
我们要存储这个绘图 app 的二进制数据 以让它符合公共数据
和公共内容
我也要为它分配扩展
这是我们在这儿需要改变的一切 咱们看一下主功能
文档类型 ShapeEditDocument 已经为我们声明好了
这种文档类型和基础文档 都是要在创建新文档时使用的 并会传递给 DocumentGroup
这个闭包参数的文档属性是个 能让我们读写底层模型的绑定 它也就是文本编辑 app 中的文本 DocumentGroup 支持原地打开 而这个绑定 让 SwiftUI 知道文本何时更新 这样它就能处理 注册撤销和文档状态的脏读 咱们看一下 ContentView 这是文档呈现的默认视图
它包含一个文本编辑器 既然我们要建一个绘图 app 我们要用一个用户能画图的画布替换它 但我们稍后再来看这个 咱们先看一下 ShapeEditDocument
这是一个符合文档协议的值类型 它是文档在磁盘上的代表 首先 我们要定义 readableContentTypes 这个一个 UTType 阵列 即统一类型标示符 SwiftUI 使用它来辨认 用户想要打开的文档类型 只有在这里才允许定义标示符 exampleText 在这里被定义了
这应该匹配 我们之前在目标 Info.plist 的 “文档类型”区域输入的内容 所以我们改一下
注意这两个声明之间的区别 这里我们使用构造函数 exportedAs 之前我们使用构造函数 importedAs 导入类是一个计算变量 因为它是导入的 这意味着它的值 会随着 app 安装或卸载而改变 这里我们使用一个导出类 让它能被声明成常量 想了解更多 请上开发者网站 参阅 UTType 说明文档 现在我们把它改成
我们自己的类
接下来 在已定义好 fileWrapper 和 contentType 的情况下 我们执行文档初始化 我们不需要这些代码 所以删去它们
contentType 参数总是受 app 支持 有几种方法执行初始化 在这里我们使用 JSONDecoder
要想使用 JSONDecoder 类型必须符合 “Codable”
针对我们的特定类型 我们也需要 把文档写入文件 我们也不需要这些 删除它们
FileWrapper 是序列化的目的地 它是一个输入输出参数 我们要么新建一个 FileWrapper 要么更新它 同样有几种方法实现 我们使用 JSONEncoder
我们只需要让它符合文件的文档协议 注意我们在使用一个值类型
这意味你能获得 使用这个结构体的一切好处 包括复制和写的行为 这样 app 能在用户还在画时就开始存储
现在有了原地文档支持 我们把我们的原型画布代码添加到项目里
我们有一个图形类 它定义了图形的属性 还有一个画布视图来展示图形
我们来改变文档中的数据类型 把它从文本改成图形类
我们再添加一些初始图形
我们也将文本编辑器置换成我们的画布
一切都搞定了 我们运行一下
我们就有了一个支持文档的绘图 app 我能保存绘画 之后再访问 在 SwiftUI 中向你的 app 添加文档支持就这么简单 谢谢观看
-
-
2:12 - DocumentGroup TextEditor
@main struct TextEdit: App { var body: some Scene { DocumentGroup(newDocument: TextDocument()) { file in TextEditor(text: file.$document.text) } } }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。