Apple launched Widgets in iOS 14 and introduced a contemporary look that modified our cellphone’s dwelling screens. The framework advanced by means of the years, including a strong technique of preserving customers up to date with their information.
iOS 17 takes widgets to the subsequent degree by introducing interactivity. Customers can now work together together with your app in a brand new, revolutionary means that wasn’t potential earlier than.
By making your app’s important actions accessible in a widget, your customers have a extra handy and fascinating option to work together together with your app.
On this tutorial, you’ll add interactive widgets to the Trask app utilizing SwiftUI.
In case you’re enthusiastic about studying SwiftUI, widgets’ easy views are an awesome place to start out with.
This tutorial covers the next subjects.
- What interactive widgets are and the way they work.
- Methods to create interactive widgets with a SwiftUI animation.
- Various kinds of interactive widgets that you could create.
- Finest practices for designing and growing interactive widgets.
Though there aren’t any strict conditions, a fundamental data of SwiftUI and WidgetKit is perhaps useful. Anyway, don’t fear, you’ll have a fast recap to start out off on the fitting foot.
Getting Began
Obtain the starter challenge by clicking the Obtain Supplies button on the prime or backside of this tutorial. Open the starter challenge (Trask.xcodeproj) within the Starter folder.
Construct and run the challenge, and it’s best to see the Trask preliminary display.
Trask is a basic tracker app that tracks totally different duties/issues/habits through the day, such because the variety of glasses of water, drugs, yoga, and so forth.
The primary time you launch the app, Trask creates some pattern information so you’ll be able to see the various kinds of duties you’ll be able to create.
- Activity with a number of steps.
- “TODO” activity with only one step.
When tapping the plus button, the app advances the duty, and as soon as it reaches its goal, it passes within the completed state.
The person can delete duties by swiping left on them and may add new ones utilizing the button on the backside of the View.
Recapping WidgetKit
Earlier than you get into the new subject of this tutorial, familiarize your self with some fundamental ideas on WidgetKit to construct widespread terminology for the remainder of the tutorial.
Including an iOS Widget
Trask comes with a static widget to observe the standing of a selectable activity.
Add an occasion of the widget to see the way it appears.
- Construct and run the challenge.
- Decrease the app.
- Lengthy press on an empty space of the display.
- Then faucet the + button, seek for Trask, and choose the widget accessible.
You’re now prepared to leap into the code construction to see the way it works.
Widget Code Construction
The TraskWidgets folder of the starter challenge accommodates all of the information associated to the widget.
Making the Widget Interactive
Information Sharing With The App
Timeline Supplier
Updating Widgets
Sorts of Interactivity
Widgets and Intents
Including the Intent
As you might even see, the widget code is contained in a separate Xcode goal, and iOS runs the widget in a course of totally different from the app. This element might sound delicate, but it surely’s essential when contemplating that the app and the widget have to share the identical information. The widget code can’t merely name some capabilities within the app goal. Among the many totally different potentialities, Trask makes use of a UserDefault
retailer on an App Group container shared between the app and the widget.
Timeline is a key idea of Widgets. To protect battery and system assets, iOS doesn’t consistently run your widget. As a substitute, it asks your timeline supplier to generate a collection of timeline entries to render your widget and current it on the proper time.
Your TaskTimelineProvider
defines three strategies.
As mentioned above, the timeline(for:in:)
returns the array of entries on the specified time, however what occurs after the final widget view is introduced? Enter the widget replace technique!
When returning the timeline of entries, you additionally present one technique for updating the timeline. Chances are you’ll select between the three choices beneath.
In our case, the Trask timeline supplier returns the .by no means
insurance policies since there isn’t any want for the widget to replace its view. The one option to replace the standing of a activity is thru the app when the person faucets to step a activity…till the subsequent chapter. :]
Wow…that was a protracted warmup, however now you’re prepared so as to add interplay to the Trask standing widget.
Beginning with iOS 17, iPadOS 17 and macOS 14, Apple permits two fundamental methods of interactivity together with your widget: buttons and toggles.
As the primary enchancment, you’ll add a step button to the Trask Standing Widget so customers can progress their favourite duties with out opening the app.
When including interactivity, the widget’s button can’t invoke code in your app, but it surely does need to depend on a public API uncovered by your app: App Intents.
App intents expose actions of your app to the system in order that iOS can carry out them when wanted. For instance, when the person interacts with the widget button.
Moreover, you can too use the identical App Intent for Siri and Shortcuts.
Firstly, add the intent technique that your button will invoke when pressed. Open TaskIntent.swift and add the carry out()
technique to TaskIntent.
The AppIntent
‘s carry out()
technique is the one referred to as when an Intent is invoked. This technique takes the chosen activity as enter and calls a technique within the retailer to progress this activity.
Please observe that UserDefaultStore
is a part of each the app and the widget extension as a way to reuse the identical code in each targets. :]
Subsequent, open TaskStore.swift and add a definition of the stepTask(_:)
technique to the protocol TaskStore.
Then, add the stepTask(_:)
technique to UserDefaultStore
. This technique masses all of the duties contained within the retailer, finds the required activity, calls the duty’s progress()
technique and saves it again within the retailer.
Lastly, add an empty stepTask(_:)
technique to SampleStore
to make it compliant with the brand new protocol definition.
-
-
TaskIntent
is an intent conforming to theWidgetConfigurationIntent
protocol. Right here, the intent permits the duty choice within the Edit Widget menu. -
TaskStatusWidget
is the precise widget. 4 elements compose the widget file.-
TaskTimelineProvider
specifies when iOS ought to refresh the widget display. -
TaskEntry
represents the mannequin of the widget view. It accommodates a date iOS makes use of to replace the widget view with the duty merchandise. -
TaskStatusWidgetEntryView
defines the widget view utilizing SwiftUI. It accommodates a timeline entry as a parameter, and it ought to lay out the widget based mostly on this parameter worth. -
TaskStatusWidget
binds all of the elements collectively inside aWidgetConfiguration
. - Lastly,
TraskWidgetBundle
declares all of the extension’s widgets.
-
placeholder(in:)
ought to return some pattern information to render the placeholder UI whereas ready for the widget to be prepared. SwiftUI applies a redaction impact to this view. -
snapshot(for:in:)
gives the information to render the widget within the gallery introduced when selecting a widget. -
timeline(for:in:)
is the principle technique that returns the timeline entries to current on the specified time.
-
.atEnd
recomputes the timeline after the final date within the timeline passes. -
.after(_:)
specifies roughly when to request a brand new timeline. -
.by no means
tells the system to by no means recompute the timeline. The app will immediate WidgetKit when a brand new timeline is offered.
- Buttons are appropriate to characterize an motion on the widget content material.
- Toggles higher determine a binary actionable state on/off. Resembling our TODO activity standing.
Be aware: On a locked gadget, buttons and toggles are inactive, and iOS doesn’t carry out actions till the person unlocks his gadget.
func carry out() async throws -> some IntentResult { UserDefaultStore().stepTask(taskEntity.activity) return .consequence() }
protocol TaskStore { func loadTasks() -> [TaskItem] func saveTasks(_ duties: [TaskItem]) func stepTask(_ activity: TaskItem) }
func stepTask(_ activity: TaskItem) { var duties = loadTasks() guard let index = duties.firstIndex(the place: { $0.id == activity.id }) else { return } duties[index].progress() saveTasks(duties) }
-
-
-
TaskIntent
is an intent conforming to theWidgetConfigurationIntent
protocol. Right here, the intent permits the duty choice within the Edit Widget menu. -
TaskStatusWidget
is the precise widget. 4 elements compose the widget file.-
TaskTimelineProvider
specifies when iOS ought to refresh the widget display. -
TaskEntry
represents the mannequin of the widget view. It accommodates a date iOS makes use of to replace the widget view with the duty merchandise. -
TaskStatusWidgetEntryView
defines the widget view utilizing SwiftUI. It accommodates a timeline entry as a parameter, and it ought to lay out the widget based mostly on this parameter worth. -
TaskStatusWidget
binds all of the elements collectively inside aWidgetConfiguration
. - Lastly,
TraskWidgetBundle
declares all of the extension’s widgets.
-
placeholder(in:)
ought to return some pattern information to render the placeholder UI whereas ready for the widget to be prepared. SwiftUI applies a redaction impact to this view. -
snapshot(for:in:)
gives the information to render the widget within the gallery introduced when selecting a widget. -
timeline(for:in:)
is the principle technique that returns the timeline entries to current on the specified time.
-
.atEnd
recomputes the timeline after the final date within the timeline passes. -
.after(_:)
specifies roughly when to request a brand new timeline. -
.by no means
tells the system to by no means recompute the timeline. The app will immediate WidgetKit when a brand new timeline is offered.
- Buttons are appropriate to characterize an motion on the widget content material.
- Toggles higher determine a binary actionable state on/off. Resembling our TODO activity standing.
Be aware: On a locked gadget, buttons and toggles are inactive, and iOS doesn’t carry out actions till the person unlocks his gadget.
func carry out() async throws -> some IntentResult { UserDefaultStore().stepTask(taskEntity.activity) return .consequence() }
protocol TaskStore { func loadTasks() -> [TaskItem] func saveTasks(_ duties: [TaskItem]) func stepTask(_ activity: TaskItem) }
func stepTask(_ activity: TaskItem) { var duties = loadTasks() guard let index = duties.firstIndex(the place: { $0.id == activity.id }) else { return } duties[index].progress() saveTasks(duties) }
-
-
TaskTimelineProvider
specifies when iOS ought to refresh the widget display. -
TaskEntry
represents the mannequin of the widget view. It accommodates a date iOS makes use of to replace the widget view with the duty merchandise. -
TaskStatusWidgetEntryView
defines the widget view utilizing SwiftUI. It accommodates a timeline entry as a parameter, and it ought to lay out the widget based mostly on this parameter worth. -
TaskStatusWidget
binds all of the elements collectively inside aWidgetConfiguration
. - Lastly,
TraskWidgetBundle
declares all of the extension’s widgets.
-
placeholder(in:)
ought to return some pattern information to render the placeholder UI whereas ready for the widget to be prepared. SwiftUI applies a redaction impact to this view. -
snapshot(for:in:)
gives the information to render the widget within the gallery introduced when selecting a widget. -
timeline(for:in:)
is the principle technique that returns the timeline entries to current on the specified time.
-
.atEnd
recomputes the timeline after the final date within the timeline passes. -
.after(_:)
specifies roughly when to request a brand new timeline. -
.by no means
tells the system to by no means recompute the timeline. The app will immediate WidgetKit when a brand new timeline is offered.
- Buttons are appropriate to characterize an motion on the widget content material.
- Toggles higher determine a binary actionable state on/off. Resembling our TODO activity standing.
Be aware: On a locked gadget, buttons and toggles are inactive, and iOS doesn’t carry out actions till the person unlocks his gadget.
func carry out() async throws -> some IntentResult {
UserDefaultStore().stepTask(taskEntity.activity)
return .consequence()
}
protocol TaskStore {
func loadTasks() -> [TaskItem]
func saveTasks(_ duties: [TaskItem])
func stepTask(_ activity: TaskItem)
}
func stepTask(_ activity: TaskItem) {
var duties = loadTasks()
guard let index = duties.firstIndex(the place: { $0.id == activity.id }) else { return }
duties[index].progress()
saveTasks(duties)
}
func stepTask(_ activity: TaskItem) {}