Build Your First iOS Widget — Part 1
Creating an emoji app and widget with SwiftUI
During WWDC 2020, Apple announced the introduction of app widgets for iOS (as well as iPadOS and MacOS). With the new WidgetKit framework, you can build widgets that can be added to your home screen to let you see important information at a glance. While you may be familiar with widgets in other operating systems, they are a completely new addition to iOS, and developers are already starting to build very exciting widgets using WidgetKit.
So let’s go ahead and build a new widget. We’re going to create a simple app I like to call Emojibook; this app will display a list of emoji along with their names, as well as more details about the emoji whenever one of them is tapped. We will create a widget that you can add to your homescreen to display an emoji, which will be updated randomly every hour or so.
Note: You’ll need Xcode 12 Beta 2 or higher to follow this tutorial.
This is what our app will look like:
Simple List-based App
Let’s start by building our simple list-based app. Open up Xcode and create a new iOS App project called Emojibook; make sure SwiftUI is selected in the Interface options and SwiftUI App is selected in the Life Cycle options.
Most of our code will be in
ContentView.swift, which we will rename to have a more descriptive name. Change the name of this file to
EmojibookListView.swift, and rename the
EmojibookListView, making sure to update its usage wherever it’s necessary (see my Xcode tricks article to learn how to do this with one click).
body section of
EmojibookListView we will add the content of our app. We will embed the content in a
NavigationView, and inside it we will add a
List, inside our
List we will add the emoji.
If you run your app, it will look something like this:
It looks good, but we want to display a different emoji on each row along with its name, not a number. To do this, we will first add an
EmojiDetails struct that will include the emoji itself, its name, and its description (we will use this description later on). Create a new file called
EmojiDetails and add the following code:
Identifiable extension is necessary to be able to identify each
EmojiDetails element when we add them to our list with the
struct. Since we will display different emoji, the emoji string itself can be used as the id.
Now we need to create a list of
EmojiDetails to be displayed in our app. Let’s create another file called
EmojiProvider, here we will add any methods needed to get the emoji data for our app. I’ve gone ahead and created a list that includes 26 distinct emoji, you can always modify it to include any emoji you want.
EmojibookListView file let’s add a reusable view called
EmojiItemView that will be used for each row of our
Now we can use our
EmojiProvider to get the list of all
EmojiDetails, and modify the
ForEach section of our
List like so:
Let’s run our app again and see how it looks.
Nice! Now let’s add a view to display an emoji’s description.
Emoji Details Sheet
To show all details about an emoji, we will use SwiftUI’s sheet component. Our sheet will look like this:
Let’s first add a reusable view called
EmojiDetailsView that will display emoji details and will be used as the sheet’s content, similar to the
EmojiItemView we added before.
To display the sheet, we will need to add a boolean binding to determine whether the sheet should be visible. We will also need to handle taps on items in our
List, and show the
EmojiDetailsView whenever a tap on an item is detected.
To handle taps on an
EmojiItemView we should first embed it in a
Button, whose action will be to toggle the
showingDetail boolean, and whose label will be the
EmojiItemView. Next we can add our sheet, bound to the
showingDetail boolean, and whose content is an
EmojiDetailsView showing details of the tapped emoji.
Now if you run your app, you should be able to tap on any emoji item and see its details:
Cool, we can finally start working on our widget!
Random Emoji Widget
Now that our simple app is done, we can finally add our emoji widget. To get started, we first need to add a Widget Extension target to our app. To do this open the File menu, select New and then select Target.
Once the menu opens up, search for ‘Widget’ and select Widget Extension. Press Next, name your widget ‘Emojibook Widget’, and make sure the Include Configuration Intent option is not selected. Press Finish and activate the widget extension scheme when prompted.
On the Project Navigator you can now see that Xcode created the Emojibook Widget folder. Go ahead and open the
Emojibook_Widget.swift file. This file includes the skeleton code required to build a widget.
One important thing to know is that the data of your widget will be provided through a
TimelineEntry, which can be updated based on your app’s use case. For example, a stock market widget that displays stock prices will probably update very frequently throughout the day.
The first thing you should see in
Emojibook_Widget.swift is a
snapshot method is used to quickly provide a
TimelineEntry to present a widget view that is used in transient situations, for example, in the widget gallery.
Then you should see the
timeline method. Through this method, you can provide an array of timeline entries, one for the present time, and others for future times based on your widget’s update interval. We will be updating our widget with a new emoji every hour, so our timeline entries will be an hour apart from each other.
Below that is the code that defines our
TimelineEntry, which we will be updating later. Then we have a
PlaceholderView struct used by iOS to display our widget on the lock screen and before rendering the widget’s content. Next is the
Emojibook_WidgetEntryView defining the visual interface of our widget. Finally we see the
Emojibook_Widget struct marked with the
@main annotation, this means that this is where the entry point of our widget is. Here we provide a
WidgetConfiguration, basically everything the operating system needs to know to display our widget: what the timeline is, how the placeholder view should look, how the actual widget should look, and our widget’s name and description.
Let’s first start by making sure we can use
EmojiProvider in our widget by adding them to our
WidgetExtension target. We can do this by selecting the file, and opening the inspector, then selecting the widget target:
Now we can define the UI of our widget. To better organize our code, we will be putting this in a separate swift file. So go ahead and create a new swift file and name it
EmojiWidgetView.swift, making sure it’s added as part of the
Emojibook WidgetExtension target.
Let’s add the content of our widget, like so:
We can now go back to
Emojibook_Widget.swift and use the view we just defined to display our widget. But before we do this, let’s add a new method in our
EmojiProvider that will give us a random
EmojiDetails object from our list of emoji. We will use this method to get a random emoji to display in our widget.
We can now modify our
TimelineEntry so that it includes an instance of
We will have to update our code so that we provide an
EmojiDetails instance wherever we create a
TimelineEntry–this should include the
snapshot method, the
timeline method, and the
PreviewProvider if you’re using live previews. This is also where we will use our
SimpleEntry(date: entryDate, emojiDetails: EmojiProvider.random())
Emojibook_WidgetEntryView, we will replace the default
Text component and use our
EmojiWidgetView, getting the
EmojiDetails from the entry.
Finally, let’s update our widget’s name and description. We can do this by updating the
Emojibook_Widget. We will only support small widgets for now, so let’s update our configuration to reflect this by adding the
supportedFamilies modifier as well.
To test our widget in the simulator we should first set our active scheme to be the
Now run your app, you should be able to see the widget in the simulator, and pressing it will open the Emojibook app.
Next up: In part 2 of this tutorial, I will show you how to support different widget sizes and adjust the widget’s content based on its size, as well as how to create deep links that open a specific view of your app when tapping on the widget. In part 3, I will show you how to use SiriKit intents to make user-configurable widgets.
To learn more about WidgetKit, make sure to use Apple’s awesome resources: