Building a Widget in SwiftUI

Aritro Paul
Level Up Coding
Published in
2 min readNov 23, 2020

--

Photo by Miguel Tomás on Unsplash

The goal is to build a widget that can fetch quotes from TronaldDump and display it on the home screen. It’ll also automatically update every 10 mins.

For this, you’ll need the latest Xcode 12 Beta.

Start a new project with iOS and then add a new target with WidgetExtension. You can delete the boilerplate code for now.

Add a Swift file named Quotes.swift. This will contain the structure and functions to get the quote.

//Structure of the quote
struct Quotes: Codable {
var value: String?
}

class QuoteController {

let url = URL(string: "https://tronalddump.io/random/quote")!
static let shared = QuoteController()


//Get a random quote from tronalddump
func getQuote(completion : @escaping(Quote)->Void) {
let session = URLSession.shared
let task = session.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
let quote = try! JSONDecoder().decode(Quote.self, from: data)
completion(quote)
}

task.resume()
}

}

This file will handle all the quote-related stuff. The next step is to head to the QuoteWidget.swift file.

The smallest element of a widget is the structure of the item inside the widget i.e. the quote

struct QuoteEntry: TimelineEntry {
var date: Date
var quote: Quote
}

The next part is the view of the Widget. It’ll show the quote from the QuoteEntry structure.

struct WidgetEntryView: View {
var entry: QuoteEntry

var body: some View {
VStack(alignment: .leading, spacing: 5) {
Text(entry.quote.value ?? "")
.italic()
.font(.caption)
Text("- Donald Trump")
.foregroundColor(.secondary)
.font(.footnote)
}
.padding()
}
}

The third part is the Content/Timeline Provider, which decides what and when to show.

struct Provider: TimelineProvider {

// Our controller class
var loader = QuoteController()

// the snapshot view shown in the widget library. It'll be constant
func snapshot(with context: Context,
completion: @escaping (QuoteEntry) -> ()) {
let entry = QuoteEntry(date: Date(), quote: Quote(value: "President of the US of A"))
completion(entry)
}

// The timeline for the widget
func timeline(with context: Context,
completion: @escaping (Timeline<QuoteEntry>) -> ()) {

//time points
let components = DateComponents(minute: 10)
let futureDate = Calendar.current.date(byAdding: components, to: Date())!

//load a quote
loader.getQuote { (quote) in
let entry = QuoteEntry(date: Date(), quote: quote)

//reload this after 10 mins
let timeline = Timeline(entries: [entry], policy: .after(futureDate))
completion(timeline)
}
}
}

And finally, the actual widget

@main
struct QuoteWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(
kind: "QuoteWidget",
provider: Provider(),
placeholder: Text("Cool Stuff by Dolan Trum"),
content: { entry in
WidgetEntryView(entry: entry)
}
)
.configurationDisplayName("Quote Widget")
.description("Shows the dumbest stuff said by Donald Trump")
}
}

Note that this uses the new @main start point in SwiftUI, which determines the starting point of the application.

With this, you will have a small widget showing dum dum quotes from Donald Trump. It’s very fascinating to work with new stuff, really ✨.

Find the complete source code here. For more in-depth stuff, I recommend John Sundell’s WWDCbySundell.

--

--