WatchOS 开发教程系列文章:
WatchOS开发教程之一: Watch App架构及生命周期
WatchOS开发教程之二: 布局适配和系统Icon设计尺寸
WatchOS开发教程之三: 导航方式和控件详解
WatchOS开发教程之四: Watch与 iPhone的通信和数据共享
WatchOS开发教程之五: 通知功能开发
WatchOS开发教程之六: 表盘功能开发
Complications
是 WatchOS 2.0引入的,它是表盘上展示的小元素,可以快速访问常用数据。当你的应用支持Complications
功能开发后, 便可以在表盘展示你应用的指定的数据,且支持直接从表盘唤醒你的 App。系统提供了一些内置的Complications
, 比如天气、日历、活动以及更多类型的数据提供内置复杂功能。
**这里所指的表盘开发, 是对表盘元素(Complications)的开发, 而不是对整个表盘(Complication)的开发, 因为整个表盘的所属权是 WatchOS。**当然, Complications
的大小和位置也是由 WatchOS决定,并基于所选表盘类型的可用空间。因为不同类型的表盘, Complications
的模板类型、可用空间、大小也不尽相同。比如, 下图是某种表盘,包含的Complications
有五个位置, 两种不同的模板类型。
Complications
功能不是必须的,但苹果官方强烈推荐 App支持此功能, 即使只是作为 App的启动器也好。好处如下:
1.当用户查看手表时, 它为你的 App提供了一个展示重要信息的机会。
2.它会将 App暂停在内存中。这样,当用户点击Complications
时,系统可以快速唤醒你的 App。
3.它为你的 App的后台任务提供了更大的预算。
要实现Complications
功能,需要将ClockKit
框架导入到 WatchKit Extension中。ClockKit
框架定义了用于实现Complications
功能的类, 以及用于提供 Apple Watch所需数据的类。比如ClockKit
中的CLKComplication
类, 它的实例就是一个表盘。
表盘的实例只有一个属性就是family
, 它代表了当前表盘的表盘系列(Complication Family), 或者理解为表盘的类型。Apple Watch支持多种Complication Family
,也定义了表盘的大小和特征。下图展示了Complication Family
以及它们在特定表盘上的显示方式。苹果官方也是鼓励 App支持所有可用Complication Family
。
再具体些, 源码中Complication Family
一共有7种
系列。具体如下:
public enum CLKComplicationFamily : Int {
case modularSmall
case modularLarge
@available(watchOS 3.0, *)
case utilitarianSmallFlat /* subset of UtilitarianSmall */
case utilitarianLarge
case circularSmall
@available(watchOS 3.0, *)
case extraLarge
}
在给定某个表盘系列(Complication Family)中,都有多种不同的表盘模板(ComplicationTemplate),你可以决定使用哪种模板来显示的数据。这些模板可以在可用空间中显示文本、图像或两者的组合, 只需要你提供数据就可以展示了。
到目前 WatchOS 4.3, 共有28种
表盘模板, WatchOS 5.0又加入了15种
表盘模板,我做了一个表盘模板汇总。下面按照表盘系列对所有模板进行了一一例举, 你可以很清楚的看到各个模板的展示方式。
① CLKComplicationTemplateModularSmallSimpleText
② CLKComplicationTemplateModularSmallSimpleImage
③ CLKComplicationTemplateModularSmallRingText
④ CLKComplicationTemplateModularSmallRingImage
⑤ CLKComplicationTemplateModularSmallStackText
⑥ CLKComplicationTemplateModularSmallStackImage
⑦ CLKComplicationTemplateModularSmallColumnsText
① CLKComplicationTemplateModularLargeStandardBody
② CLKComplicationTemplateModularLargeTallBody
③ CLKComplicationTemplateModularLargeTable
④ CLKComplicationTemplateModularLargeColumns
① CLKComplicationTemplateUtilitarianSmallSquare
② CLKComplicationTemplateUtilitarianSmallRingText
③ CLKComplicationTemplateUtilitarianSmallRingImage
① CLKComplicationTemplateUtilitarianSmallFlat
① CLKComplicationTemplateUtilitarianLargeFlat
① CLKComplicationTemplateCircularSmallSimpleText
② CLKComplicationTemplateCircularSmallSimpleImage
③ CLKComplicationTemplateCircularSmallRingText
④ CLKComplicationTemplateCircularSmallRingImage
⑤ CLKComplicationTemplateCircularSmallStackText
① CLKComplicationTemplateExtraLargeSimpleText
② CLKComplicationTemplateExtraLargeSimpleImage
③ CLKComplicationTemplateExtraLargeRingText
④ CLKComplicationTemplateExtraLargeRingImage
⑤ CLKComplicationTemplateExtraLargeStackText
⑥ CLKComplicationTemplateExtraLargeStackImage
⑦ CLKComplicationTemplateExtraLargeColumnsText
① CLKComplicationTemplateGraphicCornerGaugeText
② CLKComplicationTemplateGraphicCornerGaugeImage
③ CLKComplicationTemplateGraphicCornerTextImage
④ CLKComplicationTemplateGraphicCornerStackText
⑤ CLKComplicationTemplateGraphicCornerCircularImage
① CLKComplicationTemplateGraphicBezelCircularText
① CLKComplicationTemplateGraphicCircularImage
② CLKComplicationTemplateGraphicCircularOpenGaugeRangeText
③ CLKComplicationTemplateGraphicCircularOpenGaugeSimpleText
④ CLKComplicationTemplateGraphicCircularOpenGaugeImage
⑤ CLKComplicationTemplateGraphicCircularClosedGaugeText
⑥ CLKComplicationTemplateGraphicCircularClosedGaugeImage
① CLKComplicationTemplateGraphicRectangularLargeImage
② CLKComplicationTemplateGraphicRectangularStandardBody
③ CLKComplicationTemplateGraphicRectangularTextGauge
表盘数据源对象, 它是一个CLKComplicationDataSource
协议的遵循者, 实现了协议中的一些方法。此协议中的方法将与ClockKit
产生交互, 可以返回的过去、现在和将来的条目(TimeLineEntry)用于构建表盘元素(Complications)数据的时间轴。
每个时间轴条目(TimeLineEntry)都包含一个 NSDate
对象和一个包含要显示的数据的表盘模板。当指定的日期和精确时间到达时,ClockKit
会将相应模板中的数据渲染到Complications
中。随着时间的推移,ClockKit
会根据时间轴中的条目更新你的Complications
。
构建数据时间轴的另一个好处是,它允许用户在时间旅行(TimeTravel)期间查看更多数据。如果启用了TimeTravel
,用户可以使用Digital Crown查看或预览向Complications
提供的任何数据。
由于与表盘的交互很快发生并持续很短的时间,因此ClockKit
必须提前发现表盘元素(Complications),以确保它们能够及时显示。为了最大限度地降低功耗,ClockKit
会要求你提供尽可能多的数据,然后缓存数据并在需要时呈现数据。
当ClockKit
需要来自表盘元素(Complications)的数据时,它会运行你的 WatchKit Extension并调用表盘数据源对象的方法以获得它所需的内容。表盘数据源对象遵循CLKComplicationDataSource
协议,是你提供的对象, 系统默认是工程中的ComplicationController
对象。可以使用此协议中的方法将数据返回到ClockKit
,并提供要显示的过去、现在、将来的数据。表盘将展示这些提供的表盘数据。
在更新表盘数据的时候, 有问题需要注意。如果表盘数据没有更新,请不要调用表盘数据更新的方法, 如reloadTimelineForComplication:
或extendTimelineForComplication:
方法。请注意,后台任务和表盘数据传输都是预算编制的。如果超出预算,则在恢复预算之前无法更新表盘数据。
要支持 App的表盘开发功能,请执行以下操作:
1.配置 WatchKit Extension以告诉
ClockKit
支持表盘功能。
2.确定需要在表盘中展示的数据内容。
3.选择你的 App在每个系列中支持的模板。
4.实现表盘数据源对象(遵循CLKComplicationDataSource协议), 以此向ClockKit
提供数据。
在创建新的 Watch App时,可以要求项目支持表盘功能开发。Xcode就会自动创建Complications
所需的资源。Xcode提供了一个数据源类ComplicationController
,并配置该项目以使用该类。如果在创建Watch App时未启用表盘功能,也可以稍后启用该功能。
在创建Complications
之前,需要先确定Complications
打算展示的内容。在确定打算展示的内容时,请考虑以下因素:
1.数据能够放入可用的表盘模板中吗?数据空间有限, 可能只有少量文本字符或小图像的空间。您可以使用可用空间将信息传达给用户吗?
2.否已使用通知向用户及时传达信息?如果使用通知向用户提供更新,则Complications
可能并不比通知的方式更加显眼。
3.你可以提前提供多少数据?如果您的应用程序的数据经常更改,则可能难为Complications
提供足够的数据。更糟糕的是,如果过于频繁地刷新Complications
数据,则可能会超出后台执行或传输的预算。
4.表盘在活跃状态下, 具有Complications
功能的 App可以为后台任务提供更大的预算,但每小时的后台执行时间仍然有限。或者,可以在用户的 iPhone上生成Complications
数据并将其传输到 Watch App,但每天只能进行50次
表盘传输。具体可以参考另外一篇文章: 表盘数据传输。
如果上述这些内容你都考虑好了, 那么你就可以制定表盘数据和选择表盘模板了。苹果官方依然还是很建议支持Complications
功能的, 具体原因文章开头表明过, 故不再赘述。
先来看看关于ComplicationDataSource
协议的一些方法:
public func getSupportedTimeTravelDirections(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimeTravelDirections) -> Swift.Void)
上面的方法, 定义了 TimeTravel 的方向, 过去还是未来, 或者两者都是。
optional public func getTimelineStartDate(for complication: CLKComplication, withHandler handler: @escaping (Date?) -> Swift.Void)
optional public func getTimelineEndDate(for complication: CLKComplication, withHandler handler: @escaping (Date?) -> Swift.Void)
上面的第一个方法, 定义提供时间轴条目(TimeLineEntry)的开始时间, 如果不支持过去可以设置为当前时间。若未实现此方法,则ClockKit不会在当前条目之前检索时间轴条目。
上面的第二个方法, 定义提供时间轴条目(TimeLineEntry)的结束时间, 如果不支持过去可以设置为当前时间。若未实现此方法,则ClockKit不会在当前条目之后检索时间轴条目。
public func getCurrentTimelineEntry(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Swift.Void)
上面的方法, 定义当前想要展示在表盘元素上的时间轴条目数据。若支持过去的时间轴条目,则从此方法返回的条目必须在getTimelineEntries(for:before:limit:withHandler :)方法提供的所有条目之后。
optional public func getTimelineEntries(for complication: CLKComplication, before date: Date, limit: Int, withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Swift.Void)
optional public func getTimelineEntries(for complication: CLKComplication, after date: Date, limit: Int, withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Swift.Void)
上面的第一个方法, 定义过去的时间轴条目。返回的条目必须从过去开始,且结束日期不能迟于给定参数date。 条目间必须相隔超过一分钟, 如果两个条目相隔不到一分钟,则ClockKit会丢弃其中一个条目。
上面的第二个方法, 定义未来的时间轴条目。返回的条目必须在给定参数date之后开始。条目间必须相隔超过一分钟, 如果两个条目相隔不到一分钟,则ClockKit会丢弃其中一个条目。
optional public func getLocalizableSampleTemplate(for complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Swift.Void)
上面的方法, 获取本地化的表盘模板,该模板充当PlaceHolder的作用。当应用安装完成后, 系统会根据支持的表盘系列(ComplicationFamily)调用此方法一次,并缓存结果。
ClockKit
提供了几种在运行时更新并发症数据的方法:
1.WatchKit Extension运行时显式更新表盘数据。
2.安排后台应用程序刷新任务以更新表盘数据。
3.从 iOS App进行表盘数据传输来更新。
4.使用推送通知更新表盘数据。
每当应用为Complications
提供新数据时,请调用CLKComplicationServer
对象的reloadTimelineForComplication:
或extendTimelineForComplication:
方法来更新时间轴。前者方法删除并替换整个时间轴,而后者方法将数据添加到现有时间轴的末尾。
如果数据在可预测的时间发生变化,请考虑安排后台应用刷新任务以更新表盘数据。触发后台任务时,收集新数据(例如,使用NSURLSession后台传输)。只要您拥有更新的数据,请调用数据源reload或extend方法来更新时间轴,并安排下一个后台应用程序刷新任务。
或者,您可以在 iOS App中执行更复杂或消耗过高的数据收集任务,然后将该数据传输到手表。使用WatchConnectivity
框架通过transferCurrentComplicationUserInfo:
方法将更新发送到手表。手表收到数据,就会调用会话代理的session:didReceiveUserInfo:
方法。在此方法中,使用提供的用户信息字典更新表盘数据,然后调用数据源reload或extend方法来更新时间轴。
相关资料:
Complication Essentials
Complications Guidelines
Complication Images Guidelines
WatchOS 开发教程源码:Watch-App-Sampler