watchOS: Complications

Feb 7 2023 · Swift 5.6, watchOS 8.5, Xcode 13

Part 1: Introduction to Complications

05. Create Templates for Multiple Families

Episode complete

Play next episode

Next
About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 04. Support Multiple Families Next episode: 06. Update with Background Tasks

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Notes: 05. Create Templates for Multiple Families

The sample project in final shows implementations of almost all the supported complication types. You’ll learn about the SwiftUI-specific complications in a later episode.

Apple’s Human Interface Guidelines for watchOS contains a wealth of useful material related to complications. For example, you’ll find image size and composition guidance, descriptions of each family type and example images of how the complication family appears on the watch face.

If you’d like to dive deeper into Design Patterns, like the Factory Method design pattern that you implemented in this chapter, please check out our book, Design Patterns by Tutorials.

Heads up... You’re accessing parts of this content for free, with some sections shown as obfuscated text.

Heads up... You’re accessing parts of this content for free, with some sections shown as obfuscated text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

To put our protocol to work, we’re going to create one file per family that we’ll support. So add a Templates folder group, inside Complications, to hold all of those files.

import ClockKit

struct GraphicCircular: ComplicationTemplateFactory {

}
func template(for waterLevel: Tide) -> CLKComplicationTemplate {
    CLKComplicationTemplateGraphicCircularStackImage(
      line1ImageProvider: fullColorImageProvider(for: waterLevel),
      line2TextProvider: textProvider(for: waterLevel)
    )
}
import ClockKit

enum ComplicationTemplates {

}
  static func generate(
    for complication: CLKComplication
  ) -> ComplicationTemplateFactory? {  }
  static func generate(... {
    switch complication.family {
    case .graphicCircular: return GraphicCircular()
    }
  }
default: return nil

Updating the complication controller

Now that you’ve implemented the factory pattern, head back to ComplicationController.swift again to take advantage of your hard work.

guard
  // 1
  let factory = ComplicationTemplates.generate(for: complication),
  // 2
  let tide = Tide.getCurrent()
else {
  return nil
}

// 3
let template = factory.template(for: tide)
return .init(date: tide.date, complicationTemplate: template)
guard
...

let template = factory.template(for: tide)
return .init(date: tide.date, complicationTemplate: template)
ComplicationTemplates.generate(for: complication)?.templateForSample()

But…why?

If it’s not clear why you added the extra level of indirection, imagine your manager tells you that now you must support the .graphicBezel complication family.

supportedFamilies: [.graphicCircular, .graphicBezel]
case .graphicBezel: return GraphicBezel()
import ClockKit

struct GraphicBezel: ComplicationTemplateFactory {
  func template(for waterLevel: Tide) -> CLKComplicationTemplate {
    
  }
}
    return CLKComplicationTemplateGraphicBezelCircularText(
      circularTemplate: ~,
      textProvider: textProvider(for: waterLevel, unitStyle: .long)
    )
    🟩let circularTemplate = CLKComplicationTemplateGraphicCircularImage(
      imageProvider: ~
    )

    return CLKComplicationTemplateGraphicBezelCircularText(...)
    let circularTemplate = CLKComplicationTemplateGraphicCircularImage(
      imageProvider: 🟩fullColorImageProvider(for: waterLevel)
    )

    return CLKComplicationTemplateGraphicBezelCircularText(
      circularTemplate: 🟩circularTemplate,
      textProvider: textProvider(for: waterLevel, unitStyle: .long)
    )