Apple consistently expands the functionality of widgets with each update, making them more and more useful and popular among users. By today we have widgets on all devices — from Watches to Macs; widgets are presented in various formats — on the lock screen, and live activities. Interactivity (the ability to control the widget via buttons), a nightstand mode, and animations have been added recently.
Today, I will try to refresh your memory on the philosophy of widgets and their design. Let’s talk about the structure of a widget, what value it can bring to the user, and how Apple envisions it. I will highlight some technical aspects that may be useful if you’re just starting with your first widget or perhaps want to breathe new life into an old one.
Let’s start with an ideal example of how a widget should work from Apple’s perspective.
You pick up your phone to browse Instagram, and at a glance (1), you see a weather widget. It provides you with all the essential information you need in just one look: the weather in your (2) city: it will stop raining in 15 minutes (3), and the sun will come out. These are the three important principles that good widgets should follow:
At a glance: Don’t overload your widget with functionality. Just one glance should be enough to provide you with all the necessary information. After all, the app can be opened with a single tap. If you want to know the detailed week-long weather forecast or the number of sunny days, you can simply open the app.
Personalization: Data should be relevant to the specific user. You only care about the weather outside your window, not somewhere else.
Timeliness: A widget is not a big static app icon. Show data that is interesting to the user at the current moment in time.
By the way, while developing, you’ll notice that the entire technical implementation is based on time-related aspects.
Let’s now talk about how the widget’s technical implementation works. In short:
You provide the data.
The system sequentially renders the user interface (UI) based on this data and displays it on the home screen.
When the data runs out, the system requests new data —> go back to step 1.
Now, let's dive into more details.
When we talk about data, we refer to a Timeline
. Timeline
is an array of objects with a time reference. Each object contains all the data that is required to render the widget, plus the time when this data becomes relevant. Going back to the weather example, an object would include the air temperature, precipitation, and the time at which this weather will be relevant.
If we talk about widget as a View
, then the Timeline
is an array of ViewModels
conforming to the TimelineEntry
protocol. The only strict requirement for a TimelineEntry
is time reference.
struct WeatherEntry: TimelineEntry {
// TimelineEntry
var date: Date
// Properties
var temperature: Double
var isRaining: Bool
}
We provide the system with a timeline by implementing the TimelineProvider
, which is another protocol with methods for generating timelines. The system, in turn, handles the rendering.
In simple terms, we write the “script” for when and what to display — the timeline. The system, using the UI Widget, draws a “comic book” — a set of cards that it later presents to the user. The system itself keeps track of time and updates the widget.
Please note that precise alignment with the time you specified in the TimelineEntry date is not guaranteed.
In addition to providing a timeline, the TimelineProvider
asks you to implement the methods getSnapshot(in:completion:)
and placeholder(in:)
. In the first method, you return a timelineEntry
for rendering a skeleton in case the real data hasn’t loaded yet. The second method, `placeholder`, returns a timelineEntry
for the widget gallery. Try to use this data to show your widget’s capabilities to the user as comprehensively as possible.
In addition to the data for display, the timeline has one important property — policy: TimelineReloadPolicy
, which determines how the system will obtain new data. It comes in three options:
atEnd
- WidgetKit will request a new timeline when the current data set reaches its end.after(Date)
- WidgetKit will request a new timeline at the specific moment in time.never
- WidgetKit will keep the last available data on the screen and will not request any new data.
Furthermore, the timeline can be forcibly updated without waiting for its TimelineReloadPolicy
. We are mostly interested in 2 following cases:
WidgetCenter.shared.reloadTimelines(ofKind: “com.weatherwidget.rainstatus”)
within the app itself.
It’s important to note that updating a widget (requesting and calculating a new Timeline
) is a time-consuming process. The system imposes restrictions on the update frequency, so you can’t request a new update every minute.
There is a so-called “budget” allocated for each widget. You can read about it in detail here. But in brief, the number of available updates per day depends on the “benefit” of the widget. The system takes into account, for instance:
The documentation says that, on average, a widget can count on only 40–70 updates per day. It’s worth carefully considering the data update algorithm and choosing an appropriate TimelineReloadPolicy
to stay within these limits.
The good news is that widget updates triggered from the app or due to user interaction are “free.” Therefore, try to perform most of the work, data preparation and updates, when the app is in the foreground.
You can find a good and detailed example of optimizing the number of updates in the documentation as well.
In addition to the frequency of updates, you may also be interested in the frequency of your widget being displayed in the Smart Stack.
Users can group widgets into a stack known as the Smart Stack. The system automatically selects the most relevant widget and displays it at the top. Moreover, starting from iOS 15, the Smart Stack can even suggest widgets that the user hasn’t added to the stack (Widget Suggestions).
To help the system understand how useful at any given moment your widget is, you can use the following methods:
TimelineEntry
. Its purpose is to indicate how potentially important relative to others the current entry is.
For example, if it’s going to rain in the next hour, it would be great for the user to know this before leaving home without an umbrella. Therefore, for the timelineEntry
containing precipitation information, you can set a higher relevance score than for others. All other things being equal, Smart Stack will move your widget to the top of the stack, and the user will stay dry.
How does it work?
You provide the system with information about user actions (intents) within your app, and based on the gathered preferences and habits of the user, the system configures and displays your widget. It’s easier to understand this with an example.
Let’s say your app is called “BookAndFilmAdviser” — it suggests what to read or watch. Therefore, you have two widget configurations — one for books and one for films. Let’s assume every Friday your user looks for a new film to watch. By receiving information about these actions through App Intents, iOS will create a widget for your app in the films configuration and place it at the top of the stack next Friday.
Regarding design, there’s a good video from WWDC.
From what I remember:
ContainerRelativeShape
for corner radius.
In general, draw inspiration from the built-in system widgets in iOS to create a design that feels native and familiar to users. And here is an example of good non-system widgets:
In the end, I would just like to share useful links that will help you in the creation of the perfect widget.
Firstly, you can create widgets in different configurations, as in the example about “BooksAndFilmsAdvisor”. Secondly, even if you support iOS below 17, and you want to handle user taps, you can look at widgetURL. Well, if your users have updated their phones, you can please them with new animations and real buttons. Thirdly, do not forget about adapting the design to all platforms and environments — everything is not as difficult as it may seem. Fourth, WidgetKit is not only widgets, but also Live Activities and Watch Complications.
I hope that all that I have collected for you will inspire new ideas and achievements. Let your creativity unfold!
Even though there’s no possibility to update the widget every second, you can still display a ticking timer.