Create complications for Apple Watch
watchOS 进阶 26m

为 Apple Watch 创建复杂功能

Create complications for Apple Watch

2020年6月23日

在 Apple 官方观看视频

一句话判断

watchOS 7 彻底重构了 Complications 架构——从基于 CLKComplicationTemplate 的旧方案迁移到基于 SwiftUI 的新方案,如果你维护 Apple Watch App,这是一次不得不做的迁移。

这场 Session 讲了什么

Complications(复杂功能)是 Apple Watch 表盘上的小组件,显示来自不同 App 的关键信息。watchOS 7 引入了全新的 Complication 架构,最核心的变化是用 SwiftUI 构建表盘内容,替代了旧版的 ClockKit Template 系统。

新的架构围绕 CLKComplicationDescriptor(描述你的 Complication 的标识和支持的样式)、CLKComplicationTimelineProvider(提供时间线数据)和 SwiftUI 视图(渲染 Complication 内容)三个部分。每个 Complication 现在可以有多个族的变体,用户可以在表盘上选择不同的数据展示方式。

Session 还介绍了 Graphic Complications 的新样式——watchOS 7 的全新表盘(如 Chronograph Pro 和 X-Large)支持更丰富的图形化 Complications,包括环形进度条、角标、仪表盘等。

值得深挖的点

从 Template 到 SwiftUI 的范式转变。 旧版 Complications 使用预定义的 Template(如 CLKComplicationTemplateCircularSmallRingText),只能调整文字和颜色。新的 SwiftUI 方案让你可以自由设计 Complication 的外观,但代价是需要自己处理布局适配——表盘空间非常有限,每个像素都要精打细算。

多条 Complications 支持。 watchOS 7 允许一个 App 提供多个 Complication Descriptor。比如天气 App 可以提供”当前温度”、“未来降雨概率”两个独立的 Complication,用户在同一个表盘上可以同时添加这两个。

代码片段

import ClockKit
import SwiftUI

// 定义 Complication Descriptor
let descriptors: [CLKComplicationDescriptor] = [
    CLKComplicationDescriptor(
        identifier: "currentWeather",  // 唯一标识
        displayName: "当前天气",
        supportedFamilies: CLKComplicationFamily.allCases
    ),
    CLKComplicationDescriptor(
        identifier: "rainProbability",
        displayName: "降雨概率",
        supportedFamilies: [.graphicCircular, .graphicCorner]
    )
]
// Timeline Provider
struct WeatherTimelineProvider: CLKComplicationTimelineProvider {
    func currentTimelineEntry(
        for complication: CLKComplication,
        with date: Date
    ) -> CLKComplicationTimelineEntry? {
        let weather = fetchWeather(for: date)
        return CLKComplicationTimelineEntry(
            date: date,
            complicationTemplate: createTemplate(for: complication, weather: weather)
        )
    }
    
    func timelineEntries(
        for complication: CLKComplication,
        after date: Date,
        limit: Int
    ) -> [CLKComplicationTimelineEntry]? {
        // 提供未来的时间线条目
        let entries = (1...limit).compactMap { hour -> CLKComplicationTimelineEntry? in
            let futureDate = Calendar.current.date(byAdding: .hour, value: hour, to: date)!
            let weather = fetchWeather(for: futureDate)
            return CLKComplicationTimelineEntry(
                date: futureDate,
                complicationTemplate: createTemplate(for: complication, weather: weather)
            )
        }
        return entries
    }
}
// Graphic Circular 样式的 Complication 模板
func createTemplate(for complication: CLKComplication, weather: Weather) -> CLKComplicationTemplate {
    switch complication.family {
    case .graphicCircular:
        let template = CLKComplicationTemplateGraphicCircular(
            text: Text("\(Int(weather.temperature))°")
        )
        return template
    case .graphicCorner:
        let template = CLKComplicationTemplateGraphicCorner(
            text: Text("\(weather.condition)")
        )
        return template
    default:
        let template = CLKComplicationTemplateExtraLargeColumns(
            leadingColumn: .init(format: "\(Int(weather.temperature))"),
            trailingColumn: .init(format: "°C")
        )
        return template
    }
}

最佳实践

  • 提供多个 Complication Descriptor。 让用户选择不同的数据维度展示在表盘上,增加 App 的可见度。
  • Complication 数据要精简。 表盘空间极小,只展示最关键的一两个数字或简短文字。
  • 预生成充足的时间线数据。 Complication 不会频繁刷新,提供未来几小时的数据让系统在合适时机更新。
  • 测试所有表盘族的适配。 不同的表盘位置(圆形、矩形、角标等)需要不同的模板。

还有什么值得关注

  • watchOS 7 的共享表盘功能让用户可以分享包含自定义 Complication 的表盘配置
  • Complication 的刷新预算与 WidgetKit 类似,不要频繁请求刷新
  • 新的 Chronograph Pro 和 X-Large 表盘提供了更大的 Complication 展示区域
  • Complication 支持彩色渲染,可以在 SwiftUI 中使用彩色图标
WWDC 2020