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:

  1. Provider: Manages the timeline of our widget's content.
  2. DateEntry: Represents the data for each widget update.
  3. WidgetTestWidgetEntryView: Defines the widget's user interface.
  4. 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!

Get New Tutorials by Email

No spam. Just clear, practical breakdowns you can apply right away.

Enjoy this tutorial?

Get new practical tech tutorials in your inbox.