大多数浏览器和
Developer App 均支持流媒体播放。
-
Mac 上的 SwiftUI:收尾工作
请与我们一起了解“编程临摹课程”系列的第二部分内容,我们将使用 SwiftUI 从头到尾构建 Mac App。在此过程中,我们将探索我们的示例园艺 App 如何适应个人偏好和特定工作流程。了解 SwiftUI App 如何自动对系统设置作出反应,并探索如何使用该信息向 App 增加更多个性特征。我们将展示您如何通过设置来向人们提供自定义 App 的灵活性,并探索如何使用不同工作流程来操作个人的数据 (如拖放)。最后,我们将展示如何将数据移入和移出 app,以整合“连续互通相机”等功能来实现简单的图像导入工作流程。这是由两个部分构成的“编程临摹课程”系列的第二节内容。为了充分了解本节内容,我们建议先观看“Mac 上的 SwiftUI:构建基础”。关于使用这些框架的更多背景信息,请观看 WWDC20 的“SwiftUI 简介”。
资源
-
下载
♪ (Mac上的SwiftUI 收尾工作) 欢迎观看有关 如何在SwiftUI中 打造Mac app的第二部分内容 我是杰夫 是SwiftUI团队 的一名工程师 希望各位喜欢由我的同事马蒂厄 讲解的第一部分内容 如果您尚未观看第一部分内容 请现在前往观看 因为第二部分内容是基于 第一部分内容所讨论的各种改动 自从马蒂厄的讲解发布以来 我们的园艺app 已经取得了很大进展 SwiftUI让我们可以 在非常短的时间内 打造出一款功能丰富的app 不过 用户往往以不同的方式 使用我们的app 一款特别出色的macOS app可以说明这一点 有鉴于此 让我们看看 为所有人开发一款 app的一些方法 同时遵守马蒂厄在第一部分内容中 谈到的各项原则 首先 我们将通过 处理整个系统以及 app内部的变化 来看看作为一个完全可定制的 macOS app意味着什么 为用户添加额外的工作流 通过拖放来操作他们的数据 这样做可以提供灵活的用户体验 然后 我们将探索如何使用文件系统 使app的数据可以被导出 最后我们将增添对 “连续互通相机”的支持 以便建立一个无缝的工作流 将图像导入到我们的app 我首先想说的 不是任何特定的API 而是用SwiftUI 构建的app 如何适应macOS的自定义功能 在这里 我打开我们的园艺app 以及“系统偏好设置” 我将转换到Dark模式 您可以看到 我们的app 可以自动更新界面 虽然我打开了 “系统偏好设置” 但我也将把侧边栏图标大小更改为大 就像Dark模式一样 我们的app会根据 我在“系统偏好设置” 中的设置自动调整 作为开发者——因为 它们可以自动调整—— 和用户——因为这意味着app 将考虑到我的个人喜好—— 我喜欢这些小功能 在我离开“系统偏好设置” 以专注于我们的app之前 我想指出一点 我把强调色设置为多色 该功能使开发者可以 配置特定于app的强调色 操作系统将定制app的按钮 选择高亮显示和侧边栏符号 我希望在我的app中 支持一种强调色 所以我打开项目的资产目录 选择AccentColor 我将把它更改为系统绿 以符合app的主题 你可以看到 侧边栏图标和选择 都进行了相应的更改 我们已经看到我们的app 如何对影响整个操作系统的变化 自动作出反应 但特定于app的设置呢? 让我们来看看如何添加一个界面 好让用户定制我们的园艺app 在这里 我打开了 GardenApp文件 在WindowGroup场景旁边 我将添加一个Settings场景 该场景将为我们提供一个菜单项 当它被选中时 会打开一个带有视图的窗口 我将使用我已设置好的 SettingsView 并向它传递我的模型
另外 Settings场景还将把 适当的菜单项添加到 app的主菜单 并用Command-comma 标准键盘快捷键 来配置 这是一个很好的开始 现在 让我们看一下 SettingsView 我将在这里定义界面 在macOS中 app通常会提供 带有工具栏图标的设置界面 以实现不同窗格之间的切换 特别是如果app提供了很多设置 而这些设置又可以分成不同类别 对于我的主视图 我将使用TabView
我将为它分配两个子项: 一个用于GeneralSettings 另一个用于ViewingSettings 对于窗口工具栏区域的选项卡内容 我将使用一个tabItem 其内容可以是一个Label 我们将赋予它要显示的文本—— 在这里是“General”—— 和一个systemImage 对于GeneralSettings 我将使用“gear” 然后对ViewingSettings 如法炮制 我将添加一个tabItem 和一个 Label—— 我们称之为“Viewing”—— 以及“eyeglasses”的一个 systemImage 好了 我们有了两个选项卡的内容 现在让我们填充 GeneralSettings 当目前没有选择任何花园时 可以将一个花园作为默认花园 这对我们的用户来说是件好事 为此 我将增添 一个Picker...
我觉得第一项将是 Text("None") 对于其他项 我将对我们数据中的 所有花园添加一个ForEach
对于每个花园 我将添加一个Text 为花园设置名称 及其displayYear 我们还需要提供一个 带有花园ID的标签 对于“None“”值 我们可以设置一个None的标签
对于其他的花园 我们将设置一个 与花园ID对应的标签
最后 我们需要为 Picker的选择 提供某种状态 在提供像这样的设置界面时 必须保持那种状态 以便您的app在 启动和操作系统更新时 记住用户的选择 在SwiftUI中 可以使用 AppStorage属性包装器 来实现这一点 该属性包装器将使用 UserDefaults系统 来保持化我们的值 这正是我们在这里所需要的 对于选择绑定 我将添加 AppStorage属性包装器 这需要一个秘钥 我们赋予它“defaultGarden” 并将其命名为“selection” 这也是可选的Garden.ID 这将利用用户默认系统 来保持我们的选择值 我还会添加一个fixedSize 到我的Picker 并填充表单
我将切换到ContentView 并添加我们的AppStorage 赋予它我们使用的同一个秘钥
我们将称之为 “defaultGardenID” 这也是可选的Garden.ID 对于这个选这项绑定 我要用一个Binding替换它 “get”会首先使用 selectedGardenID 如果这个没有设置 我们会退回到 defaultGardenID 对于setter 我们只想更新我们的 selectedGardenID 我们其实不想更新 我们的defaultGarden 因此 我只会说 “selectedGardenID = $0” 好了 我将运行我们的app 在这里打开偏好菜单项 选择Indoor Plants 作为默认花园 我将打开一个新窗口 我们看到 Indoor Plants被选中 通过设置来提供定制支持 是为用户营造灵活体验的一种好方法 另一种方法是为同一个操作 提供可选工作流 在第一部分内容中 马蒂厄向大家展示了 如何添加一个主菜单项 为选定的花园添加植物 这对我们的app来说 是一个很不错的功能 但让我们看看另一种方法 我们可以通过一种常见的macOS 用户交互方式提供类似的功能: 拖放 由于我们在这里 使用的是table 所以我要做一些调整 以便支持它作为拖放源 和拖放目的地 我首先要做的是 从初始化程序中 移除这个“plants” 然后 我将在最后 添加一个行构建器 对于这个行构建器的内容 我将添加一个ForEach 并使用我们以前的那些植物
对于每株植物 我会分别创建一个TableRow 现在 我将通过添加 itemProvider修饰符 来定制每个taberows 我将在这里返回 plant.itemProvider 这是我在模型上建立的一个计算属性 现在 每行都可以成为一个拖放源 我现在已经做了足够的改变 可以拖出我的植物 如果没有东西接受它 这个功能不是很有用 解决方法是在表中添加拖放支持 onInsert修饰符是 拖放等式的另一半 它接受一个内容类型列表 我将在这里传递 Plant.draggableType 这是我在模型上设置的 一个自定义类型 它还接受一个闭包 该闭包传递两个参数 一个参数是拖放操作发生位置的索引 另一个是 item providers列表 然后我们将调用 Plant.fromItemProviders 以创建我们的模型 我们将在这里传递 item providers 这将返回一份植物列表 我们可以利用该列表 来更新我们的模型 我将在索引处调用 garden.plants.insert (contentsOf: plants)
现在 我可以用Indoor Plants打开一个新窗口 从Backyard Flower Bed中 选择一些花 并拖动复制
拖放是在app内 移动数据的好方法 但在app和操作系统之间 移动数据呢? 用户肯定希望 能够导出所有这些数据—— 可能是为了备份 或导入到另一个app 为了方便这一工作流 让我们添加一个主菜单项 将数据库导出为一种 可以与其他app 共享的公共文件格式 我已经创建了一个类型 来包含我的菜单项 它符合命令协议 在这里的命令中 我将添加一个 ImportExportCommands 并向它传递store 现在让我们切换到这个文件 对于body 我将添加一个 CommandGroup 并替换系统提供的 importExport放置 这将把我们的菜单项添加到 File菜单中的预期位置 对于CommandGroup 的内容 我将添加一个Section 和一个Button 我将赋予一个“Export”标签 后面跟着省略号 省略号向用户表明 选择那一项 将打开一个窗口或者保存对话框 Button可以修改某种状态 比如说 “isShowingExport = true” 我们把那个状态也加进来
现在 我们有了Button 它可以修改某种状态 我还将在这里添加 fileExporter修饰符 我将让它与其 isPresented参数中的 状态绑定 isShowingExport 也接受文档 这种类型需要符合 文件文档协议 或引用文件文档协议 我已经将一致性 添加到我的store 所以我们在这里传递它 另外 它还接受一个内容类型 我们将赋予它 Store.readableContentTypes.first 这是CSV类型 最后 它接受一个闭包 该闭包传递操作的结果 表明是成功还是失败 现在 我选择Export 菜单项 给它赋予一个保存文件 比如“plants.csv” 点击Export 该文件被保存到硬盘 关于在app和操作系统之间 移动数据的话题 我还想说明最后一点 我们的app有很多 关于植物的文本数据 但要是能添加图像就更好了 用户可能会在一段时间内 拍摄植物的照片 以跟踪它们的生长情况 实现这种导入流的一个方法是 使用连续互通相机功能 该功能使用户可以 用iOS设备拍摄植物的照片 并把照片直接导入到app 让我们看看当用户在 图库视图中选择了植物时 我们如何添加菜单项 来实现这一工作流 在importExportCommands后面 我将添加 ImportFromDevicesCommands 这将为我们提供主菜单项 另外 我将切换到 GardenDetail文件 在body结尾处 我将添加 importsItemProviders修饰符 它接受我们希望支持导入的 类型列表 为此我将依据是否有项目被选中 在这里我将使用我们的选择 如果为空 则返回一个空数组 如果不为空 则返回 Plant.importImageTypes 这是系统上所有图像类型的列表 该修饰符接受一个闭包 该闭包传递 item providers列表 我们将接受那些providers 并调用 Plant.importImageFromProviders 向它传递providers 这将返回一个URL 这是图像在硬盘上的保存位置 然后 我们将更新模型 方法是遍历所有被选中的ID
以及获取对该植物的引用 并更新其imageURL 我将选择 Indoor Plants花园 并切换到Gallery模式 我将把图像放大一点 在这里选择植物 在主菜单项中 选择从iPhone > Take Photo导入
您可以看到 我们的相册更新了 我希望您通过本视频掌握了 开发Mac app的一些好方法 我期待着各位的app 将让macOS平台变得更好 祝大家拥有一个 愉快的WWDC 2021 ♪
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。