watchOS: Complications

Feb 7 2023 Swift 5.6, watchOS 8.5, Xcode 13

Part 2: Tinted & Custom Complications

13. Display a SwiftUI View in a Complication

Episode complete

About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 12. Refactor SwiftUI Views

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

Take your career further with a Kodeco Pro subscription. 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.

For more information on watchOS development, check out our book watchOS With SwiftUI by Tutorials

For more information about complications, check out these resources:

Heads up... You've reached locked video content where the transcript will be shown as obfuscated text.

After all of that work, it’s time to wrap this project up and check out your SwiftUI view in a complication.

Event to timeline entry

All the complication methods need to be able to create a CLKComplicationTimelineEntry from an EKEvent.

import EventKit
private func timelineEntry(for ekEvent: EKEvent?) -> CLKComplicationTimelineEntry {

  let event: Event?
  if let ekEvent = ekEvent {
    event = Event(ekEvent: ekEvent)
  } else {
    event = nil
  let template = CLKComplicationTemplateGraphicRectangularFullView(
    EventComplicationView(event: event)
  return .init(
    date: event?.startDate ?? .now,
    complicationTemplate: template

Localizable sample

As we learned earlier in the course, it’s important to have a sample complication for users to see when they’re choosing complications.

func localizableSampleTemplate(
  for complication: CLKComplication
) async -> CLKComplicationTemplate? {

  let start =
    bySettingHour: 10, minute: 0, second: 0, of: .now
  let end =
    byAdding: .hour, value: 1, to: start
  return CLKComplicationTemplateGraphicRectangularFullView(
    EventView(event: .init(
      color: .blue,
      startDate: start,
      endDate: end,
      title: "Gnomes rule!",
      location: "Everywhere"

The current appointment

Just like when using non-SwiftUI templates, you have to provide the current timeline entry if one exists.

return timelineEntry(for: EventStore.shared.nextEvent)

Future appointments

It is likely you have more than one event on your calendar every day.

func timelineEntries(
  for complication: CLKComplication,
  after date: Date,
  limit: Int
) async -> [CLKComplicationTimelineEntry]? {

  guard let events = EventStore.shared.eventsForToday() else {
    return [timelineEntry(for: nil)]
  let wanted = events
    .filter {$0.startDate) == .orderedAscending
    .map { timelineEntry(for: $0) }
  return wanted.count > 0 ? wanted : [timelineEntry(for: nil)]


In EventView.swift, just after the .foregroundColor(event.color) line of RoundedRectangle, add the complication foreground modifier

.previewContext(faceColor: .green)