Getting Started With watchOS 9 Complications in WidgetKit | by Alex Bartiş | Nov, 2022

An In-depth Guide to Build an Amazing Daily Quotes App

photo by alvaro perez Feather unsplash

I recently had some fun adding complications to my strength training app strength++, as I went straight to the “new” WidgetKit framework. It’s not really new, but what’s new in wOS 9 is that you can use WidgetKit instead of the old ClockKit to create complications for the clock.

Let’s not waste much time and get to work. you will get the code HereBoth the initial version if you want to code along and the final version if you want to see everything.

We’re using the Dailyquote app built for this purpose, which shares most of its code base between the iOS and watchOS apps. The iOS app is targeting iOS 16, and watchOS is, of course, the minimal version of WOS 9.

App running on both watch and iphone simulator
App running on both watch and iphone simulator

We need to add an extension for complications first, so in Xcode, go to File -> New -> Target, select the watchOS tab, and then choose Widget Extensions.

Xcode New Target watchOS Widget Extension
Xcode New Target watchOS Widget Extension
  • Tap Next.
  • Enter product name.

I went for the DailyQuote complications.

  • Uncheck Include Configuration Intent, because the complexities we’re building today are not configurable
  • Make sure your project is selected in the dropdown and embed is also set to your watch app.
configure target

Tap Finish and Activate to activate your new goal.

activate new target

Now you can see in the project navigator that under the name you provided earlier there is a new folder containing a swift file, an assets folder and a Info.plist file. Go ahead and open the newly created Swift file, and let’s start designing our widgets.

At this point, I want you to open this link This is the official documentation for what we’re doing here, and if I don’t give you enough information or you have some questions, you may find the answer.

Your Complexity Will Be Done By The Hard Lifting For The UI EntryView structure, which in my case is DailyQuote_ComplicationsEntryView,

Let’s first add a property to identify the widget family we’re designing for:

struct DailyQuote_ComplicationsEntryView : View @Environment(\.widgetFamily) var widgetFamilyvar entry: Provider.Entry
var body: some View
Text(, style: .time)

so i have added widgetFamily variable, which is pulling from Environment to object to the price, well, widgetFamily, At this point, you need to understand how complications are grouped. There are four groups leading to WOS complications:

  • accessoryInline
  • accessoryCorner
  • accessoryRectangular
  • accessoryCircular

You can choose and support whoever you want, but today we’ll go and create the complications for each. So let’s create four SwiftUI Views:

One of the ideas of each complexity is Text At the point where I applied:

  • widgetAccentableWhich adds the scene and all its subviews to the utterance group.
  • unredactedwhich tells the OS that that specific scene doesn’t need to be modified at any point (meaning blurring)

Now let’s go back EntryView And add our ideas to each widget family:

Now, let’s add some previews to all our complications.

  • go to _preview structwho was born
  • existing duplicate EntryView four times for each type of complication

You will now have four previews in the canvas.

Something’s starting to show, isn’t it?

Now, I won’t go into the design for each complication type, in the end, it’s your choice how you want it to look, but I’ll go into my favorites: corner,

For this specific one, I’ve added an image from SF symbols (note, it shows up as small, so think about it when designing complications) and used widgetLabel Celebration. This function, according to Apple, “creates a label to display additional content outside the main SwiftUI view of an accessory family widget.” That’s the short version.

Alt + Tap To read the full documentation on that.

For now the last thing we’ll do for the UI side is to update Widget Structure to better “describe” our widget to the system and users. so, go to struct DailyQuote_Complications: Widget and update it:

We just did the following:

  • hardcoded a kind which is a unique identifier for this widget (if you will have more)
  • updated configurationDisplayNameis the name that shows up in our complexities as complexity picker
  • One description Shown for the widget when a user adds or edits a widget

driven by your complexity TimelineEntry… Entries. so Xcode generated this SimpleEntry: TimelineEntrywhich we now need to rename QuoteEntry,

and add a new property to it, a Quote,

struct QuoteEntry: TimelineEntry let date: Datelet quote: Quote

don’t forget to add Quote For targeted membership of the Complexity extension.

Now your entire file is red because every instantiation of QuoteEntry is missing Quote parameter. Let’s start updating them.

the first is func placeholder(in context: context) -> QuoteEntry.
This method returns a hardcoded QuoteEntry To use in specific scenarios where the OS shows your complexity in a “sensitive” context (if you need to read more on this, see the docs).

func placeholder(in context: Context) -> QuoteEntry let quote = Quote(quote: "Roses are red", author: "Nobody knows")return QuoteEntry(date: Date(), quote: quote)

is at the front func getSnapshot(in context: Context, completion: @escaping (QuoteEntry) -> ()) Which, according to Apple, is a timeline entry that represents the current time and position of a widget. In this scenario, we need to treat the two cases based on context, as the context can be a preview of the complexity or the actual complexity running on the clock.

For this we need to bring QuoteManager So declare it in our struct (and again, don’t forget to set its target membership). If we’re not seeing the preview, we really want to get an actual quote out of our data layer.

The last thing we need to do is actually create a timeline for our widget, so let’s go and modify getTimeline(),

In case it’s not self-explanatory, we’re creating a timeline of five entries, one minute apart, and each pulling a different quote from our storage.

We have the data and the UI, so let’s modify all of our Complication a. think with QuoteEntry property, which will be passed from EntryView, we will also set .quote property from entry as parameter for Text on our UI.

Hint: At this point, you need to reset the target membership Quotes.json File for complexity extension target.

And that’s it! Running the Complications goal on a clock simulator (and of course using Complications) now shows off our sexy new complications with a fancy daily quote.

see what he says,

Thanks for reading.

Leave a Reply