介绍
在WWDC 2015上,Apple宣布了对Apple Watch软件watchOS 2的首次重大更新。 此新更新为开发人员带来了许多新的API和功能,供开发人员使用,包括本机应用程序,对更多Apple Watch硬件的访问以及与父iOS应用程序更好的通信。
在本教程中,我将向您展示如何利用另一个新功能,即使用ClockKit框架创建自定义手表并发症的功能。 本教程要求您在OS X Yosemite (10.10)或更高版本上运行Xcode 7 。
如果您还不了解,Apple Watch的复杂之处在于可以在表盘上显示信息的小界面元素。

上面的屏幕截图显示了除右上角的时间外, 模块化表盘上还显示了五种并发症。
1.设置项目
使用watchOS>应用程序> iOS应用程序和WatchKit App模板在Xcode中创建一个新项目。

接下来,如下所示配置项目,确保选中了“ 包括复杂性”。

Xcode创建您的项目后,在Project Navigator中打开ClockKit Introduction WatchKit Extension 。 您将看到一个新的Complications Configuration部分,如下所示。

受支持家族下的五个复选框代表您的应用程序支持的不同并发症家族。 在本教程中,我们将重点介绍Modular Large系列。 您现在可以取消选中其他复选框。

如苹果的 watchOS 2 Transition Guide ,强烈建议您的应用支持所有五个系列。 下图显示了使用这些不同系列的位置。

2.设置并发症
为了教您如何使用ClockKit,您将创建一个简单的复杂功能,在一天中的特定电视台上显示假电视节目的时间,名称和类型。
首先,在ClockKit Introduction WatchKit Extension文件夹中打开ComplicationController.swift 。 Xcode已自动为您创建了此文件。 它包含一个ComplicationController
类,该类符合并实现CLKComplicationDataSource
协议。
与该协议关联的方法是如何向ClockKit提供有关您要显示的并发症的数据。 协议的方法包含一个处理程序,必须调用该处理程序才能将数据传递回ClockKit。
时间线
在向ClockKit提供数据时,您是以时间轴的形式进行的。 为此,您可以使用链接到特定时间点的数据对象填充并发症的时间轴。 这些数据对象由CLKComplicationTimelineEntry
类建模。 当达到特定时间点时,ClockKit会自动为您的应用显示正确的内容。
ClockKit会在计划显示时间之前早已检索和缓存您的时间线条目。 这意味着必须能够预先检索和计划数据。 每个应用程序都有有限的时间预算来在后台刷新其内容。 换句话说,复杂性不能代替推送通知或通知中心。
通过这种方式提供数据的主要好处是可以维持出色的用户体验。 用户抬起手腕时,每种并发症的内容立即可用。 使用此时间轴数据模型的另一个好处是能够轻松采用watchOS 2中的新“ 时光旅行”功能。这是当用户在看着表盘的同时转动数字表冠并且复杂性数据反映出时间时那已经去了 。
在代码中的“ 时间轴配置”标记下,您将看到配置时间轴所需的四种方法。 为了使本教程简单易懂,我们仅支持向前旅行,并提供长达24小时的数据。 为此,更新了前三种方法的实现,如下所示。
func getSupportedTimeTravelDirectionsForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTimeTravelDirections) -> Void) {
handler(.Forward)
}
func getTimelineStartDateForComplication(complication: CLKComplication, withHandler handler: (NSDate?) -> Void) {
handler(NSDate())
}
func getTimelineEndDateForComplication(complication: CLKComplication, withHandler handler: (NSDate?) -> Void) {
handler(NSDate(timeIntervalSinceNow: (60 * 60 * 24)))
}
“ 时间轴配置”部分中的第四个方法getPrivacyBehaviorForComplication(_:withHandler:)
用于指定在锁定设备时是否希望显示并发症的内容。 传递给处理程序的默认值ShowOnLockScreen
意味着数据将始终可见。
范本
滚动到ComplicationController
类的底部,然后找到getPlaceHolderTemplateForComplication(_:withHandler:)
方法。 在此方法中,您将创建一个CLKComplicationTemplate
并将其传递回要显示的数据的处理程序。 在本教程中,您将使用CLKComplicationTemplateModularLargeStandardBody
模板,该模板显示三行文本。 对于每个电视节目,这三行将是:
- 开始和结束时间
- 名称
- 类型
在五个并发症家族中有相当多的模板可用。 下图显示了可用的模板,并突出显示了本教程中将要使用的模板。

文字提供者
由于手表显示屏上的内容空间有限,在小尺寸的表盘表面复杂情况下甚至更多,因此,您可以使用CLKTextProvider
对象将基于文本的数据提供给ClockKit。 这些提供程序旨在避免截断内容,从而导致不良的用户体验。 使用这些文本提供程序,您可以描述想要显示的内容的意图,然后ClockKit为您处理最终的格式。
例如,如果要在并发症中显示日期,请使用带有指定日期和一组单位(月,日,小时等)的CLKDateTextProvider
。 这将正确格式化可用空间的日期。 例如,将日期设置为“ 10月22日,星期四”,然后将其格式设置为:
- 10月22日,星期四
- 10月22日,星期四
- 十月22
- 22
有关ClockKit中可用的文本提供程序和模板的完整列表,请查看Apple的ClockKit框架参考 。
既然您已经了解了基本模板和文本提供程序,那么您就可以为并发症创建模板了。 在getPlaceHolderTemplateForComplication(_:withHandler:)
方法中,添加以下代码:
func getPlaceholderTemplateForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTemplate?) -> Void) {
// This method will be called once per supported complication, and the results will be cached
let template = CLKComplicationTemplateModularLargeStandardBody()
template.headerTextProvider = CLKTimeIntervalTextProvider(startDate: NSDate(), endDate: NSDate(timeIntervalSinceNow: 60 * 60 * 1.5))
template.body1TextProvider = CLKSimpleTextProvider(text: "Show Name", shortText: "Name")
template.body2TextProvider = CLKSimpleTextProvider(text: "Show Genre", shortText: nil)
handler(template)
}
使用此代码,您可以为Modular Large系列创建Standard Body模板,并为其提供三个文本提供程序。 CLKSimpleTextProvider
对象应该简单明了。 CLKTimeIntervalTextProvider
接受两个日期并将其格式化为字符串,例如“ 10:00 AM-3:30PM”或“ 1:00-2:45PM”。
3.测试并发症
现在,我们已经配置了时间线并为ClockKit提供了用于复杂化的模板,我们终于可以测试我们的工作结果。 在Xcode窗口的左上方,选择并发症目标和可用的模拟器之一。 单击播放按钮以构建并运行您的应用程序。

启动Apple Watch模拟器时,很可能会看到以下表盘:

要测试您的并发症,您需要完成一些步骤。
第1步
按Command + Shift + 2以模拟强制触摸,然后在表盘上单击。

第2步
按Command + Shift + 1 ,向右滑动至模块化面,然后单击“ 自定义”按钮。

第三步
使用触控板或鼠标向右滑动,点击中间的并发症,然后滚动至底部,以模拟数字表冠。

第4步
再次模拟力度触摸以返回到表盘选择器并选择“ 模块化 ”表盘。

恭喜你 您刚刚获得了第一个ClockKit并发症,它出现在Apple Watch表盘上。 现在是时候开始用一些实际的(伪)数据填充它了。
4.向ClockKit提供数据
在为复杂性创建任何时间线条目之前,我们首先将创建一个Show
结构以轻松地对我们的数据进行建模,然后创建此新类型的值。 在ComplicationController
类定义的开始之前,将以下代码片段添加到ComplicationController.swift中 。
struct Show {
var name: String
var shortName: String?
var genre: String
var startDate: NSDate
var length: NSTimeInterval
}
let hour: NSTimeInterval = 60 * 60
let shows = [
Show(name: "Into the Wild", shortName: "Into Wild", genre: "Documentary", startDate: NSDate(), length: hour * 1.5),
Show(name: "24/7", shortName: nil, genre: "Drama", startDate: NSDate(timeIntervalSinceNow: hour * 1.5), length: hour),
Show(name: "How to become rich", shortName: "Become Rich", genre: "Documentary", startDate: NSDate(timeIntervalSinceNow: hour * 2.5), length: hour * 3),
Show(name: "NET Daily", shortName: nil, genre: "News", startDate: NSDate(timeIntervalSinceNow: hour * 5.5), length: hour)
]
如您所见,我们创建Show
结构并创建一个包含四个显示的静态数组。 您将使用此数组作为并发症的数据源。
在ComplicationController
类中,找到getCurrentTimelineEntryForComplication(_:withHandler:)
方法,并向其中添加以下代码:
func getCurrentTimelineEntryForComplication(complication: CLKComplication, withHandler handler: ((CLKComplicationTimelineEntry?) -> Void)) {
// Call the handler with the current timeline entry
let show = shows[0]
let template = CLKComplicationTemplateModularLargeStandardBody()
template.headerTextProvider = CLKTimeIntervalTextProvider(startDate: show.startDate, endDate: NSDate(timeInterval: show.length, sinceDate: show.startDate))
template.body1TextProvider = CLKSimpleTextProvider(text: show.name, shortText: show.shortName)
template.body2TextProvider = CLKSimpleTextProvider(text: show.genre, shortText: nil)
let entry = CLKComplicationTimelineEntry(date: NSDate(timeInterval: hour * -0.25, sinceDate: show.startDate), complicationTemplate: template)
handler(entry)
}
首先,您像以前一样创建一个并发症模板,并在其中填充内容。 然后,使用两个参数创建一个CLKComplicationTimelineEntry
对象:
- 一个约会
- 模板
您在此处指定的日期是该条目在时间轴上的位置,并显示给用户。 对于我们的应用,我们为时间轴条目提供了一个在节目开始前十五分钟的日期,以便它可以在节目开始前显示在用户的手表上。
接下来,您需要向ClockKit提供您为并发症创建的所有其他节目。 这是在getTimelineEntriesForComplication(_:afterDate:limit:withHandler:)
方法中完成的。 使用此方法中的limit参数,以便单个应用程序不会使ClockKit缓存中的数据过载,并且确切知道它需要提供多少个时间轴条目。
下面的代码添加到getTimelineEntriesForComplication(_:afterDate:limit:withHandler:)
在ComplicationController.swift方法:
func getTimelineEntriesForComplication(complication: CLKComplication, afterDate date: NSDate, limit: Int, withHandler handler: (([CLKComplicationTimelineEntry]?) -> Void)) {
// Call the handler with the timeline entries after to the given date
var entries: [CLKComplicationTimelineEntry] = []
for show in shows
{
if entries.count < limit && show.startDate.timeIntervalSinceDate(date) > 0
{
let template = CLKComplicationTemplateModularLargeStandardBody()
template.headerTextProvider = CLKTimeIntervalTextProvider(startDate: show.startDate, endDate: NSDate(timeInterval: show.length, sinceDate: show.startDate))
template.body1TextProvider = CLKSimpleTextProvider(text: show.name, shortText: show.shortName)
template.body2TextProvider = CLKSimpleTextProvider(text: show.genre, shortText: nil)
let entry = CLKComplicationTimelineEntry(date: NSDate(timeInterval: hour * -0.25, sinceDate: show.startDate), complicationTemplate: template)
entries.append(entry)
}
}
handler(entries)
}
您首先创建一个空的CLKComplicationTimelineEntry
对象数组。 然后,您遍历之前创建的节目。 对于每个节目,如果它在ClockKit提供的日期之后开始并且没有超过条目的限制,那么您可以创建一个模板并将其附加到数组中。
在此方法的最后,您将使用数组调用处理程序。 将nil
或空数组传递给处理程序将告诉ClockKit您没有更多数据可提供,它将停止查询CLKComplicationDataSource
对象,直到需要更多数据为止。
有了这些方法,您现在就可以看到完成的并发症。 单击播放按钮以构建并运行您的应用程序。 模拟器首次启动时,您会看到并发症,其中显示了您创建的第一个节目的数据。

如果您随后使用触控板或鼠标滚动以进入“时光旅行”模式,您会发现并发症在正确的时间点显示了您创建的其他节目。

结论
在本教程中,您学习了ClockKit框架的基础知识,以及如何为Apple Watch创建自定义表盘并发症。 这包括五个并发症系列,基本模板和文本提供程序以及基于时间轴的数据。
麻烦的是,您还内置了对watchOS 2时间旅行功能的支持,并随着时间的推移添加了新数据。 与往常一样,如果您有任何意见或问题,请将其保留在下面的评论中。
翻译自: https://code.tutsplus.com/tutorials/an-introduction-to-clockkit--cms-24247