大多数浏览器和
Developer App 均支持流媒体播放。
-
为小组件构建 SwiftUI 视图
小组件是来自 app 的小块信息,用户可以选择将其放在主屏幕或 Today view 中。了解使用 SwiftUI 从头开始构建小组件视图的过程。复习你需要了解用于特定小组件构造的句法,学习如何合并这些命令并自定义小组件界面,从而获得出色的浏览体验。 要了解更多有关小组件的信息,请确保了解“ 小组件编程临摹课程”。
资源
- Building Widgets Using WidgetKit and SwiftUI
- Creating a widget extension
- Human Interface Guidelines: Widgets
- Keeping a widget up to date
- Learn more about creating widgets
- WidgetKit
相关视频
WWDC21
WWDC20
-
下载
(你好)
你好 欢迎来到 WWDC
(为小组件构建 SWIFTUI 视图) 我是 Niles 我是 iOS 系统体验团队的一名工程师 今天 我将向你展示 如何为小组件构建 SwiftUI 视图
首先 我们来谈谈 SwiftUI 如何启用小组件 然后在本节的主要部分 我们会一起构建一个小组件视图 最后 我们将介绍一些新的 API 这些新 API 让我们可以很好地 使用 SwiftUI 来构建小组件 让我们直接开始吧 (小组件中的 SWIFTUI) 通过 SwiftUI 和 WidgetKit 你可以提供视图的时间线 以便适当的时候在主屏幕上显示 得益于 SwiftUI 的适应性 你可以编写小组件 并将其部署到 iOS 和 macOS 中 因为小组件是独立使用的 并且是 iOS 14 和 macOS Big Sur 中的新功能 即使你需要将 app 部署到 可能无法使用 SwiftUI 的旧版操作系统中 小组件也是我们 学习和使用 SwiftUI 的绝佳机会 我不知道你的情况 但我最近喝了很多咖啡 有些日子 我喝得有点多了 (CAFFEINE DRINKS) 所以我创建了一个 app 来记录和追踪我喝的含咖啡因的饮料 并估计出我体内咖啡因的含量 我称它为“Wired”
我认为对 app 来说 小组件是一个很好的补充 它让我能随时知道自己体内的咖啡因含量 这就是我想要的小部件 (咖啡因 65.97 毫克 卡布奇诺 8 分 56 秒之前) 首先 你可以看到它使用的是 我的 app 视觉识别和配色方案
顶部显示的是目前我体内的咖啡因含量 底部显示的是我最近一次 所喝咖啡因饮料的名称及时间
请注意 咖啡因含量的背景形状 与小组件的形状同心
另外 我希望小组件底部的时长 可以实时更新以保证始终是正确的
让我们在演示中来看看 SwiftUI 是如何让这一切变得简单的
我已经设置好 在时间轴上读取的小组件配置 以便我们可以在此 专注地创建小组件视图 我将使用 SwiftUI 来创建此小组件视图 这意味着我这里编写的所有东西 都可以在你的 app 中使用
这是我的视图 然后这是预览图 我正在用 WidgetPreviewContext 来指定预览中要显示的小组件系列 在这种情况下是小型规格的组件
首先 让我们为 驱动 UI 的数据定义一个结构
我称之为 CaffeineWidgetData 它包括三个属性 咖啡因数量 、饮料名称以及饮用日期 我还有一个用于一些预览值的稳定常量 以让我的预览图看起来更加真实
让我们把这一属性 添加到视图中以保存此数据
接下来 让我们更新预览以使用预览数据
我们准备开始构建视图 让我们先添加一些内容
我正在用 VStack 来垂直堆叠视图 顶部是“caffeine”一词 正文字体加粗 并使用了我在资产目录中 定义的自定义颜色
下方是数量 它的字体更大但外观相似
由于这个字体挺大的 我想让它根据版面需要缩小一点 所以我在这里设置了一个最小比例系数
接下来 让我们 使用 ZStack 给小组件添加背景色 从而赋予其一些个性特征 ZStack 允许你将视图叠加在一起
你注意到我们的小组件会自动地 从系统中获取它的形状、大小和角半径
现在 让我们继续构建小组件 添加我最后喝的饮料名称和饮用时间
自我最后一次喝咖啡以来的这段时间 你可以看到 我正在对文本使用新的初始化表达式 它带有日期和样式从而为你格式化文本 使用此初始化表达式时 内容会随着时间的推移 自动地从指定日期开始向上或向下计数 这是个让小组件在主屏幕上 显得生动有趣地好方法 让我们点击画布中的“实时预览”按钮 来看看小组件会呈现出怎样的视图 你可以看到时长正在不断增加
(咖啡因 56.23 毫克) 我甚至可以使用字符串插值 来为字符串添加更多内容 所以我可以像这样添加 “ago”一词
因为这是用的字符串插值 所以框架会给你生成一个本地化的密钥 这样该格式就可适用于其他地区和语言
事实上 我们这里有两组内容 如文本颜色所示: 上面的棕色文本和下面的白色文本 所以我们把它们分成两个 VStack 并在中间添加一个 spacer 部件 我将回到这里并点击此文本 选择“Embed in VStack”
把此文本移到 VStack 里面
接下来 我将对此文本执行相同的操作 点击“Embed in VStack”
然后把第二个文本移到里面
并在它们中间添加一个 spacer 部件
我要让这两个 VStack 都是前导对齐的 要在画布中做到这点 我可以点击属性检查器中 垂直堆栈部分的前导按钮
这里
以及这里
这开始变得有点复杂了 所以我打算把顶部和底部的部分 提取到它们各自的子视图中 因为这是 SwiftU 它的视图很便宜 所以我几乎可以免费完成这个操作
我点击这里的 VStack 然后选择“ExtractedView” 让我们称之为“CaffeineAmountView”
让我们添加一个属性以保存一些数据
然后 我要对底部的 VStack 执行同样的操作 单击“Extractsubview” 让我们称之为“Drinkview”
让我们也给它添加同样的属性
最后 让我们传入一些数据
虽然小组件看起来是一样的 但是我们用了更好的代码结构来构建它
我希望我的内容是前导对齐而不是居中的 我将把 CaffeineAmountView 的内容 包装在一个 HStack 中 并在末尾添加一个 spacer 部件 点击“Embed in HStack”
HStack 也就是 “水平堆栈” 可以让你把视图相邻放置 通过在末尾添加一个 spacer 部件 我是在告诉布局系统 将我的内容推到相反方向的边缘 也就是前导边缘处 因为我不需要任何最小间距 所以我将指定最小间距为零 这样我的内容就可以占用尽可能多的空间
让我们给内容添加一些 padding 让它看起来更加美观 因为这是 SwiftUI 所以我可以将光标放在主 VStack 上 使用画布来完成这个操作
然后在属性检查器的 padding 部分 点击这四个复选框
你可以看到 我没有为该 padding 指定一个值 SwiftUI 将为它运行的设备和配置 使用一个合适的默认值
我想强调 CaffeineAmountView 因此我打算给它设置一个背景
我使用了资产目录中 名为“latte”的颜色
让我们点击属性检查器中的四个复选框 再次添加一些 padding
这有点太多了 我们把它设成八个
你可以看到这个形状的角不是圆角 正如 《Human Interface Guidelines for Widgets》中所描述的那样 圆角矩形 是小组件视觉设计语言的重要组成部分 所以我要把这个形状的角磨圆
我可以使用 cornerRadius 修饰符 像这样
然后试着找到一个看起来不错的值 但不同的设备的组件可能使用不同的半径 所以这可能会变得有点麻烦
我们在 iOS14 中 使用新的 ContainerRelativeShape 这为实现这点提供了一个更好的方法
ContainerRelativeShape 是一个全新的形状类型 它将采用由父级指定的 最接近的容器形状的路径 并根据形状的位置使用适当的角半径 在这个例子中 系统正在为我们的小组件定义容器形状 我们非常容易获得了与其同心的角半径
如果更改了 我们的主 VStack 的 padding 值 CaffeineAmountView 的 角半径就会发生变化 从而使它周围的边界 在角的曲线周围保持一个恒定的厚度
最后 让我们使用一个 spacer 部件 为最重要的内容提供一些呼吸空间
好了 我们已经实现了我们想要的设计 我个人认为它看起来很漂亮 我迫不及待地想将其添加到主屏幕中 让我们看看 我的小部件在深色模式下的样子 为此 让我复制预览 并添加修饰符以将其设置为深色模式
由于我所有的颜色都来自资产目录 我在资产目录中 为它们定义了深色外观差异 所以我的小组件会自动应用深色模式
我妈妈也会喝很多咖啡 因此我敢肯定 Wired 会让她感到很兴奋 但是对她来说 底部的文本可能太小而很难阅读 因此 让我们更新小组件以支持动态类型 以便她和所有 喜欢较大文本的用户都可使用这一组件
首先 我们添加一个新的预览 以检查小组件在较大尺寸类别下的外观图
在这里 我将尺寸类别 设置为 ExtraExtraExtraLarge
看起来不错 由于 SwiftUI 具备自适应特性 我无需更改任何内容即可支持动态类型 而且我无需进行其他工作 就构建了一个包容性更强的小组件 是不是很神奇? 接下来 我想谈谈占位符 为了获得出色的小组件体验 你应该提供一个占位符 供系统在你的扩展程序中请求视图 或设备被锁定时使用 你的占位符应该看起来像你的小组件 但没有任何特定的内容 让我们看看如何修改视图 使其也能作为占位符使用 首先 我将通过复制现有的预览 来创建另一个预览
然后我将为它添加 “is placeholder true”修饰符 使它成为一个占位符
你可以看到 SwiftUI 会自动地 用圆角矩形替换我所有的文本内容 并以与它们替换的内容 所匹配的方式对它们进行样式设置
而如果我想在占位符中保留一些文本内容 我可以为其添加 “is placeholder false”修饰符 让我们把它添加到“caffeine”一词中
就像那样 我更新了视图以将其用作小组件的占位符 很简单 对吗? 我刚刚向你展示的 “is placeholder”修饰符 将会在之后的版本中提供 你可能知道小组件分为三个不同的系列: 小型、中型和大型规格 让我们看看将小组件 更新到另一个小组件系列有多么简单 让我们首先 为中型规格添加一个预览
这看起来不错 但有点浪费空间
在我的 app 中 我会让用户在登录时提供他们的饮料照片 所以 将这些照片置于小部件中 可以让我们更好地利用屏幕空间 首先 我要在数据结构中添加这一属性 以保存该照片的名称
然后从预览资产目录中添加一张示例照片
让我们把照片添加到视图中 我们只希望饮料照片 出现在中型规格的小组件上 为了能够创建此条件下的布局 让我们为小组件系列 添加一个 Environment 变量
我希望我的照片出现在现有内容的旁边 所以 我要把所有内容包装在一个 HStack 中
然后 如果我们是在 中型规格小组件中 并且有要显示的照片 我们要添加图像
并使其可调整大小
太棒了
最后 让我们通过添加另一个预览 来看看我们的尺寸占位符 我敢肯定 你开始摸到窍门了 我是复制现有的预览图 然后给它添加一个修饰符 让其成为一个占位符
你可以看到 SwiftUI 知道 自动用填充色替换图片的内容 因此 我无需做任何其他工作 即可创建中型规格组件占位符 非常棒 对吧? 这就是使用 SwiftUI 可以多么容易地构建小组件视图 让我来介绍一下 我刚刚在演示中向你展示的两个新的 API
首先 让我们看一下 如何使小组件的角半径看起来更漂亮 嵌套圆角矩形时 大多数时候 你不想它们使用相同的角半径 相反 你希望它们是同心的
在 iOS14 中 我们可以毫不费力实现这点 将新的 ContainerRelativeShape 设置为你的视图背景 SwiftUI 会从这里接手下面的工作 这非常简单
在 iOS14 中 我们在 Text 上添加了新的初始化表达式 以根据样式来格式化日期 这使你可以创建倒数计时、计时器 以及其他样式的绝对日期和相对日期 由于这会随着时间的流逝而自动更新 因此 这是一种 使小组件在主屏幕上栩栩如生的好方法
让我们来总结一下 SwiftUI 使你能够为用户 构建引人入胜的小组件体验 小组件会利用 SwiftUI 对自适应布局的现有支持
我们添加了新的 API 以便我们可以更轻松地 在小组件中执行常见的某些操作 请注意 这些 API 不仅可用于小组件中 还可用于其他任何地方 因此你也可以在 app 中使用它们 (下一步) 一定要查看“Meet WidgetKit”讲座部分 以进一步了解小组件时间线的更多信息 还有我的同事 Izzy 谈到的“Widgets Code-along”部分 看他是如何使用 WidgetKit 从头开始构建小组件的 希望大家在 WWDC 度过一段愉快的时间 谢谢大家 明年再见
-
-
18:40 - Concentric corner radius with ContainerRelativeShape
// Concentric corner radius with ContainerRelativeShape struct PillView : View { var title: Text var color: Color var body: some View { Text(title) .background(ContainerRelativeShape().fill(color)) } }
-
19:09 - Displaying date and time
// Displaying date and time // June 3, 2019 Text(event.startDate, style: .date) // 11:23PM Text(event.startDate, style: .time) // 9:30AM - 3:30PM Text(event.startDate...event.endDate) // +2 hours // -3 months Text(event.startDate, style: .offset) // 2 hours, 23 minutes – Automatically updating as time pass Text(event.startDate, style: .relative) // 36:59:01 – Automatically updating as time pass Text(event.startDate, style: .timer)
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。