An In-depth Guide to Build an Amazing Daily Quotes App
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.
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.
- 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.
Tap Finish and Activate to activate your new goal.
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
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(entry.date, 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:
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
EntryViewfour 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:
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
kindwhich is a unique identifier for this widget (if you will have more)
configurationDisplayNameis the name that shows up in our complexities as complexity picker
descriptionShown 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
and add a new property to it, a
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
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.
Thanks for reading.