This session is a Code Along session, the session project can be found here.
What is a Widget?
A widget is a SwiftUI view that updates over time, how and when it updates is covered in this and the following sessions.
How to add a widget to an existing app
Create a new Widget target:
File > New > Target > Widget Extension
This will create a new target with a new project folder associated with it.
In this folder we have one .swift file, named after our widget, which declares:
a
Widget, which contains your widget declarationa placeholder
View, which is a view WidgetKit uses to render the widget for the first timean entryView`, which is the default view used by the widget
import WidgetKit
import SwiftUI
import Intents
struct Provider: IntentTimelineProvider {
public func snapshot(for configuration: ConfigurationIntent, with context: Context, completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date(), configuration: configuration)
completion(entry)
}
public func timeline(for configuration: ConfigurationIntent, with context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
var entries: [SimpleEntry] = []
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
let currentDate = Date()
for hourOffset in 0 ..< 5 {
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
let entry = SimpleEntry(date: entryDate, configuration: configuration)
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
struct SimpleEntry: TimelineEntry {
public let date: Date
public let configuration: ConfigurationIntent
}
struct PlaceholderView : View {
var body: some View {
Text("Placeholder View")
}
}
struct WWDCNotesWidgetEntryView : View {
var entry: Provider.Entry
var body: some View {
Text(entry.date, style: .time)
}
}
@main
struct WWDCNotesWidget: Widget {
private let kind: String = "WWDCNotesWidget"
public var body: some WidgetConfiguration {
IntentConfiguration(kind: kind, intent: ConfigurationIntent.self, provider: Provider(), placeholder: PlaceholderView()) { entry in
WWDCNotesWidgetEntryView(entry: entry)
}
.configurationDisplayName("My Widget")
.description("This is an example widget.")
}
}
struct WWDCNotesWidget_Previews: PreviewProvider {
static var previews: some View {
WWDCNotesWidgetEntryView(entry: SimpleEntry(date: Date(), configuration: ConfigurationIntent()))
.previewContext(WidgetPreviewContext(family: .systemSmall))
}
}in the
Widgetdeclaration, update the default configuration with your widget title and description (those are two modifiers,.configurationDisplayNameand.description)declare which widget family/sizes you’d like to support by adding a
.supportedfamilies(_:)modifier, by default all three families are supported.the dynamic data of the widget should come from your
TimelineEntry: any required data should be defined there.TimelineEntryinstances come from ourTimelineProvider: we will need to update ourTimelineProviderdefinition by adding the necessary entry data in thesnapshot(for:with:completion:)andtimeline(for:with:completion:)functions
Tips
Use
.previewContent(WidgetPreviewContext(family: .system..))on SwiftUI previews to display the widget layout.use the
.isPlaceholder(true)modifier on the preview view (note:.isPlaceholderis not available as of Xcode 12b2)
