WidgetKit Series 4 : Creating a Dynamic Day of the Week Widget in SwiftUI
In this tutorial, we'll walk through the process of creating a dynamic widget for iOS that displays the current day of the week along with a corresponding emoji. This widget updates throughout the week, providing a fun and informative addition to your users' home screens.
Setting Up the Widget
First, let's break down the main components of our widget:
- Provider: Manages the timeline of our widget's content.
- DateEntry: Represents the data for each widget update.
- WidgetTestWidgetEntryView: Defines the widget's user interface.
- WidgetTestWidget: Configures the widget itself.
The Provider
The Provider
struct conforms to TimelineProvider
and is responsible for generating the content timeline for our widget:
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> DateEntry {
DateEntry(date: Date())
}
func getSnapshot(in context: Context, completion: @escaping (DateEntry) -> ()) {
let entry = DateEntry(date: Date())
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
var entries: [DateEntry] = []
let currentDate = Date()
for hourOffset in 0 ..< 5 {
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
let entry = DateEntry(date: entryDate)
entries.append(entry)
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
This provider creates a timeline with entries for the next 5 hours, ensuring our widget stays up-to-date throughout the day.
The DateEntry
Our DateEntry
struct holds the date information and provides a computed emoji
property based on the day of the week:
struct DateEntry: TimelineEntry {
let date: Date
var emoji: String {
let weekday = Calendar.current.component(.weekday, from: date)
switch weekday {
case 1: return "😎" // Sunday
case 2: return "😫" // Monday
case 3: return "😊" // Tuesday
case 4: return "🤓" // Wednesday
case 5: return "🤔" // Thursday
case 6: return "🥳" // Friday
case 7: return "😴" // Saturday
default: return "🤖"
}
}
}
This clever use of a computed property allows us to display a different emoji for each day of the week.
The Widget View
The WidgetTestWidgetEntryView
struct defines how our widget looks:
struct WidgetTestWidgetEntryView : View {
var entry: DateEntry
var body: some View {
ZStack {
ContainerRelativeShape()
.fill(LinearGradient(
gradient: Gradient(colors: [.cyan, .green]),
startPoint: .topLeading,
endPoint: .bottomTrailing
))
VStack {
Text("\(entry.emoji)")
.font(.system(size: 50))
Text(entry.date.formatted(.dateTime.weekday(.wide)))
.font(.title3)
.fontWeight(.bold)
.foregroundStyle(.white.opacity(0.7))
Text(entry.date.formatted(.dateTime.day()))
.font(.largeTitle)
.bold()
.foregroundStyle(.white.opacity(0.7))
}
.padding()
}
}
}
This view creates a visually appealing widget with a gradient background, the day's emoji, the name of the day, and the date.
The Widget Configuration
Finally, we define our widget using the WidgetTestWidget
struct:
struct WidgetTestWidget: Widget {
let kind: String = "WidgetTestWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
if #available(iOS 17.0, *) {
WidgetTestWidgetEntryView(entry: entry)
.containerBackground(.fill.tertiary, for: .widget)
} else {
WidgetTestWidgetEntryView(entry: entry)
.padding()
.background(Color.black)
}
}
.configurationDisplayName("My Widget")
.description("This is an example widget.")
.contentMarginsDisabled()
}
}
This configuration sets up our widget with the appropriate provider and view, and includes compatibility checks for different iOS versions.
Conclusion
With this code, we've created a dynamic, visually appealing widget that displays the current day of the week along with a fun emoji. The widget updates throughout the week, providing users with a quick and enjoyable way to check the day at a glance.
Remember to add this widget to your app's target and enable it in the capabilities section of your project settings. Happy coding!