WatchOS开发教程之六: 表盘功能开发
Posted DCSnail-蜗牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WatchOS开发教程之六: 表盘功能开发相关的知识,希望对你有一定的参考价值。
WatchOS 开发教程系列文章:
WatchOS开发教程之一: Watch App架构及生命周期
WatchOS开发教程之二: 布局适配和系统Icon设计尺寸
WatchOS开发教程之三: 导航方式和控件详解
WatchOS开发教程之四: Watch与 iPhone的通信和数据共享
WatchOS开发教程之五: 通知功能开发
WatchOS开发教程之六: 表盘功能开发
表盘开发简介(Complications)
Complications
是 WatchOS 2.0引入的,它是表盘上展示的小元素,可以快速访问常用数据。当你的应用支持Complications
功能开发后, 便可以在表盘展示你应用的指定的数据,且支持直接从表盘唤醒你的 App。系统提供了一些内置的Complications
, 比如天气、日历、活动以及更多类型的数据提供内置复杂功能。
**这里所指的表盘开发, 是对表盘元素(Complications)的开发, 而不是对整个表盘(Complication)的开发, 因为整个表盘的所属权是 WatchOS。**当然, Complications
的大小和位置也是由 WatchOS决定,并基于所选表盘类型的可用空间。因为不同类型的表盘, Complications
的模板类型、可用空间、大小也不尽相同。比如, 下图是某种表盘,包含的Complications
有五个位置, 两种不同的模板类型。
![](https://image.cha138.com/20230223/cbc177c1a0bd4eff827d8ef3b809b6aa.jpg)
表盘开发的好处
Complications
功能不是必须的,但苹果官方强烈推荐 App支持此功能, 即使只是作为 App的启动器也好。好处如下:
1.当用户查看手表时, 它为你的 App提供了一个展示重要信息的机会。
2.它会将 App暂停在内存中。这样,当用户点击Complications
时,系统可以快速唤醒你的 App。
3.它为你的 App的后台任务提供了更大的预算。
表盘和模板的类型
要实现Complications
功能,需要将ClockKit
框架导入到 WatchKit Extension中。ClockKit
框架定义了用于实现Complications
功能的类, 以及用于提供 Apple Watch所需数据的类。比如ClockKit
中的CLKComplication
类, 它的实例就是一个表盘。
表盘系列(Complication Family)
表盘的实例只有一个属性就是family
, 它代表了当前表盘的表盘系列(Complication Family), 或者理解为表盘的类型。Apple Watch支持多种Complication Family
,也定义了表盘的大小和特征。下图展示了Complication Family
以及它们在特定表盘上的显示方式。苹果官方也是鼓励 App支持所有可用Complication Family
。
![](https://image.cha138.com/20230223/624e7a0c1ce348c2b8e334340b078e25.jpg)
再具体些, 源码中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
表盘模板(ComplicationTemplate)
在给定某个表盘系列(Complication Family)中,都有多种不同的表盘模板(ComplicationTemplate),你可以决定使用哪种模板来显示的数据。这些模板可以在可用空间中显示文本、图像或两者的组合, 只需要你提供数据就可以展示了。
到目前 WatchOS 4.3, 共有28种
表盘模板, WatchOS 5.0又加入了15种
表盘模板,我做了一个表盘模板汇总。下面按照表盘系列对所有模板进行了一一例举, 你可以很清楚的看到各个模板的展示方式。
CLKComplicationFamilyModularSmall
① CLKComplicationTemplateModularSmallSimpleText
![](https://image.cha138.com/20230223/ca10b758665a4b6d994ad379b375d1b1.jpg)
② CLKComplicationTemplateModularSmallSimpleImage
![](https://image.cha138.com/20230223/eaedfbdb06994ef3ac93f7fcc52ba44f.jpg)
③ CLKComplicationTemplateModularSmallRingText
![](https://image.cha138.com/20230223/4c820b760b8a43fea549a9a069c6707b.jpg)
④ CLKComplicationTemplateModularSmallRingImage
![](https://image.cha138.com/20230223/8953288cce074cf08eb21c870643b47e.jpg)
⑤ CLKComplicationTemplateModularSmallStackText
![](https://image.cha138.com/20230223/48830b915c0d42c8a2c7a02ec7a45428.jpg)
⑥ CLKComplicationTemplateModularSmallStackImage
![](https://image.cha138.com/20230223/ce3792a7dcd148e99da2792c4a79f0a5.jpg)
⑦ CLKComplicationTemplateModularSmallColumnsText
![](https://image.cha138.com/20230223/7e190b043a1f4f88a89644eed553082a.jpg)
CLKComplicationFamilyModularLarge
① CLKComplicationTemplateModularLargeStandardBody
![](https://image.cha138.com/20230223/94f858ca3b584431843a9fa7b037d9d6.jpg)
② CLKComplicationTemplateModularLargeTallBody
![](https://image.cha138.com/20230223/38a9b9530f04401d9cfe42362e67c250.jpg)
③ CLKComplicationTemplateModularLargeTable
![](https://image.cha138.com/20230223/b69419e714bb4e16afcc79cf163be1f5.jpg)
④ CLKComplicationTemplateModularLargeColumns
![](https://image.cha138.com/20230223/13801b69d6484a8e840a2a79a611050f.jpg)
CLKComplicationFamilyUtilitarianSmall
① CLKComplicationTemplateUtilitarianSmallSquare
![](https://image.cha138.com/20230223/096419019a9646e38f59870eac4525e1.jpg)
② CLKComplicationTemplateUtilitarianSmallRingText
![](https://image.cha138.com/20230223/0aca5c47e4484c348e7d52d6ed7c7e5a.jpg)
③ CLKComplicationTemplateUtilitarianSmallRingImage
![](https://image.cha138.com/20230223/6736d789d3f04dcca4cb910c95c7cd4a.jpg)
CLKComplicationFamilyUtilitarianSmallFlat
① CLKComplicationTemplateUtilitarianSmallFlat
![](https://image.cha138.com/20230223/0e97a218f9c743c89444166ff24bdfd3.jpg)
CLKComplicationFamilyUtilitarianLarge
① CLKComplicationTemplateUtilitarianLargeFlat
![](https://image.cha138.com/20230223/50de8a9b7a434cc0a568b966657cf274.jpg)
CLKComplicationFamilyCircularSmall
① CLKComplicationTemplateCircularSmallSimpleText
![](https://image.cha138.com/20230223/03975f279bee4a9ebfcc39b22bd9f1d6.jpg)
② CLKComplicationTemplateCircularSmallSimpleImage
![](https://image.cha138.com/20230223/fa7faf6b04944476bd61022949b2f5e6.jpg)
③ CLKComplicationTemplateCircularSmallRingText
![](https://image.cha138.com/20230223/2c1f69fc222047e59f2e055406f8e6ee.jpg)
④ CLKComplicationTemplateCircularSmallRingImage
![](https://image.cha138.com/20230223/c9044c9420224d39840fb068968b13de.jpg)
⑤ CLKComplicationTemplateCircularSmallStackText
![](https://image.cha138.com/20230223/f3d9a79b6a954886a770f72058862071.jpg)
CLKComplicationFamilyExtraLarge(watchOS 3.0)
① CLKComplicationTemplateExtraLargeSimpleText
![](https://image.cha138.com/20230223/5edd573d154d4633ad9d0f4c471c5f94.jpg)
② CLKComplicationTemplateExtraLargeSimpleImage
![](https://image.cha138.com/20230223/dcd65d07465843e098ce12a57ed2d6f6.jpg)
③ CLKComplicationTemplateExtraLargeRingText
![](https://image.cha138.com/20230223/ba52e059093d4a86b7bd16e8810e4a15.jpg)
④ CLKComplicationTemplateExtraLargeRingImage
![](https://image.cha138.com/20230223/a85e71131b5841d7bfa5f90d96267f4f.jpg)
⑤ CLKComplicationTemplateExtraLargeStackText
![](https://image.cha138.com/20230223/6c2c9d23646744458d1611d985582c64.jpg)
⑥ CLKComplicationTemplateExtraLargeStackImage
![](https://image.cha138.com/20230223/46cea9c3c254483487c201f1ab76d911.jpg)
⑦ CLKComplicationTemplateExtraLargeColumnsText
![](https://image.cha138.com/20230223/7e811ca668954167929490dafe15d001.jpg)
CLKComplicationFamilyGraphicCorner(watchOS 5.0)
① CLKComplicationTemplateGraphicCornerGaugeText
![](https://image.cha138.com/20230223/8506477868904ed0aec523868a6aa12d.jpg)
② CLKComplicationTemplateGraphicCornerGaugeImage
![](https://image.cha138.com/20230223/3e54cd14f43f4ce696dd8cca0bca4354.jpg)
③ CLKComplicationTemplateGraphicCornerTextImage
![](https://image.cha138.com/20230223/565cdd818d7f4e8abe4eafc0564bca58.jpg)
④ CLKComplicationTemplateGraphicCornerStackText
![](https://image.cha138.com/20230223/d901a823017a49398439e6c33a318f4e.jpg)
⑤ CLKComplicationTemplateGraphicCornerCircularImage
![](https://image.cha138.com/20230223/edef459850684433801ccedcb3efcc56.jpg)
CLKComplicationFamilyGraphicBezel(watchOS 5.0)
① CLKComplicationTemplateGraphicBezelCircularText
![](https://image.cha138.com/20230223/ad718900875f401ea351d97ea825d341.jpg)
CLKComplicationFamilyGraphicCircular(watchOS 5.0)
① CLKComplicationTemplateGraphicCircularImage
![](https://image.cha138.com/20230223/21cd8a7b4c4642849a847593d82b442e.jpg)
② CLKComplicationTemplateGraphicCircularOpenGaugeRangeText
![](https://image.cha138.com/20230223/a35437b4be6e42c3a3a5042d9d2a3aff.jpg)
③ CLKComplicationTemplateGraphicCircularOpenGaugeSimpleText
![](https://image.cha138.com/20230223/24cc9a157f064a55877d5e1d1dd53c70.jpg)
④ CLKComplicationTemplateGraphicCircularOpenGaugeImage
![](https://image.cha138.com/20230223/85bfb5f0dbff4f6085ae32ee3524245b.jpg)
⑤ CLKComplicationTemplateGraphicCircularClosedGaugeText
![](https://image.cha138.com/20230223/0d1e86ddc9a441c3b3e57a091da3b90a.jpg)
⑥ CLKComplicationTemplateGraphicCircularClosedGaugeImage
![](https://image.cha138.com/20230223/b0a834f1482e4c8f841e5ba93f2fb920.jpg)
CLKComplicationFamilyGraphicRectangular(watchOS 5.0)
① CLKComplicationTemplateGraphicRectangularLargeImage
![](https://image.cha138.com/20230223/0c6751335c214b8e85fb06d14f8c0776.jpg)
② CLKComplicationTemplateGraphicRectangularStandardBody
![](https://image.cha138.com/20230223/5c139f9994b94085a284aa80e6583dcb.jpg)
③ CLKComplicationTemplateGraphicRectangularTextGauge
![](https://image.cha138.com/20230223/7b5d40d7d15742e9a2249c570aa5dc87.jpg)
时间轴(TimeLine)
表盘数据源对象, 它是一个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
提供数据。
配置 WatchKit Extension
在创建新的 Watch App时,可以要求项目支持表盘功能开发。Xcode就会自动创建Complications
所需的资源。Xcode提供了一个数据源类ComplicationController
,并配置该项目以使用该类。如果在创建Watch App时未启用表盘功能,也可以稍后启用该功能。
设计表盘元素(Complications)
在创建Complications
之前,需要先确定Complications
打算展示的内容。在确定打算展示的内容时,请考虑以下因素:
1.数据能够放入可用的表盘模板中吗?数据空间有限, 可能只有少量文本字符或小图像的空间。您可以使用可用空间将信息传达给用户吗?
2.否已使用通知向用户及时传达信息?如果使用通知向用户提供更新,则Complications
可能并不比通知的方式更加显眼。
3.你可以提前提供多少数据?如果您的应用程序的数据经常更改,则可能难为Complications
提供足够的数据。更糟糕的是,如果过于频繁地刷新Complications
数据,则可能会超出后台执行或传输的预算。
4.表盘在活跃状态下, 具有Complications
功能的 App可以为后台任务提供更大的预算,但每小时的后台执行时间仍然有限。或者,可以在用户的 iPhone上生成Complications
数据并将其传输到 Watch App,但每天只能进行50次
表盘传输。具体可以参考另外一篇文章: 表盘数据传输。
如果上述这些内容你都考虑好了, 那么你就可以制定表盘数据和选择表盘模板了。苹果官方依然还是很建议支持Complications
功能的, 具体原因文章开头表明过, 故不再赘述。
表盘数据源配置(ComplicationDataSource)
先来看看关于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
以上是关于WatchOS开发教程之六: 表盘功能开发的主要内容,如果未能解决你的问题,请参考以下文章
WatchOS开发教程之一: Watch App架构及生命周期