WWDC22: 复杂组件
复杂组件是 watchOS 关键的组成部分,它提供快速地一览重要信息的途径,通过点击,可以定位到应用。从 watchOS 5 开始,富组件功能又提供了使用图像内容即更多组件样式的能力。在 watchOS 7 加入 SwiftUI 后,复杂组件到达了一个新阶段。今天借助于 WidgetKit,复杂组件功能再次更新,使其以小组件的形式,把一览信息的体验带到 iOS 中。
基于最新的 WidgetKit,只要一次开发,就可以同时发布到 iOS 16 和 watchOS 9 ,实现一致的一览信息体验。这是因为现在有了新的 WidgetFamily
类型,以 accessory
开头的。
// WidgetFamily additions
public enum WidgetFamily {
// ...
// 适合摘要、刻度盘或者进度条
case accessoryCircular
// 适合多行文本、小图片或图表,与 `ClockKit` 的 `.graphicRectangular` 类似
case accessoryRectangular
// 显示在时间上的简短文本
case accessoryInline
// watchOS only
case accessoryCorner
}
颜色
为了保持一致性,新的 accessory widget 主要由系统控制样式和布局,开发者可以根据系统当前渲染模式进行适配:full-color, accented, vibrant。
public struct WidgetRenderingMode {
static var fullColor: WidgetRenderingMode
static var accented: WidgetRenderingMode
static var vibrant: WidgetRenderingMode
}
struct MyWidgetView: View {
// 从环境变量获取渲染模式
@Environment(\.widgetRenderingMode) var renderingMode
var body: some View {
switch renderingMode {
...
}
}
}
full-color mode
在 watchOS 上会按照设计的样式,如渐变色等,完全展示出来。
accented mode
视图会被分为两组,强调内容和默认内容。要设置为强调内容,可以使用 .widgetAccentable()
修改器。
vibrant mode
在 iOS 中,widget 的内容首先会被去色,然后调整亮度以适应锁屏界面界面的样式,同时会增加毛玻璃背景,让内容显示跟清晰。
ZStack {
// 背景
AccessoryWidgetBackground()
// 内容
VStack {
Text("Mon")
Text("6")
.font(.title)
}
}
实践
添加新的 accessory families
WidgetKit 中原有的 system family 在手表上不可用,所以需要用平台宏命令进行区分
struct EmojiRangerWidget: Widget {
public var body: some WidgetConfiguration {
// ...
#if os(watchOS)
.supportedFamilies([.accessoryCircular,
.accessoryRectangular, .accessoryInline])
#else
.supportedFamilies([.accessoryCircular,
.accessoryRectangular, .accessoryInline,
.systemSmall, .systemMedium])
为 watchOS 适配 IntentRecommendation
API
因为在 iOS 中动态 widget 可以直接在界面中进行设置编辑,而在 watchOS 中,需要提供一个预配置好的列表,供用户选择,为此可以在 IntentTimelineProvider
中重写 recommendations
方法,接口参考:
public protocol IntentTimlineProvider {
// ...
associatedtype Intent : INIntent
/// 提供一个可供用户在表单中选择的 intent configuration 建议集合
func recommendations() -> [IntentRecommendation<INIntent>]
// ...
}
public struct IntentRecommendation<Intent> where Intent : INIntent {
public init(intent: Intent, description: Text)
public init(intent: Intent, description: LocalizedStringKey)
public init<S>(intent: Intent, description: S) where S : StringProtocol
}
新的 SwiftUI ProgressView
新的.accessoryCircular
很适合使用新的环形进度条视图展示内容,基于 SwiftUI 的进度条是图可以自动更新。
case .accessoryCircular:
ProgressView(interval: entry.character.injuryDate...entry.character.fullHealthDate,
countdown: false,
label: { Text(entry.character.name) },
currentValueLabel: {
Avatar(character: entry.character, includeBackground: false)
})
.progressViewStyle(.circular)
区分主次
case .accessoryRectangular:
HStack(alignment: .center, spacing: 0) {
VStack(alignment: .leading) {
// 主要内容
Text(entry.character.name)
// 突出字体
.font(.headline)
// 突出颜色
.widgetAccentable()
Text("Level \(entry.character.level)")
Text(entry.character.fullHealthDate, style: .timer)
}.frame(maxWidth: .infinity, alignment: .leading)
Avatar(character: entry.character, includeBackground: false)
}
其他
在 watchOS 中使用 @Environment(\.isLuminanceReduced) var isLuminanceReduced
判断屏幕状态,可以动态的调整内容。
@Environment(\.isLuminanceReduced)
var isLuminanceReduced
var body: some View {
if isLuminanceReduced {
Text("🙈").font(.title)
} else {
Text("🐵").font(.title)
}
}