Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
SwiftUI Essentials – iOS 14 Edition

You're reading from  SwiftUI Essentials – iOS 14 Edition

Product type Book
Published in May 2021
Publisher Packt
ISBN-13 9781801813228
Pages 494 pages
Edition 1st Edition
Languages
Author (1):
Neil Smyth Neil Smyth
Profile icon Neil Smyth

Table of Contents (56) Chapters

1. Start Here 2. Joining the Apple Developer Program 3. Installing Xcode 12 and the iOS 14 SDK 4. An Introduction to Xcode 12 Playgrounds 5. Swift Data Types, Constants and Variables 6. Swift Operators and Expressions 7. Swift Control Flow 8. The Swift Switch Statement 9. Swift Functions, Methods and Closures 10. The Basics of Swift Object-Oriented Programming 11. An Introduction to Swift Subclassing and Extensions 12. An Introduction to Swift Structures and Enumerations 13. An Introduction to Swift Property Wrappers 14. Working with Array and Dictionary Collections in Swift 15. Understanding Error Handling in Swift 5 16. An Overview of SwiftUI 17. Using Xcode in SwiftUI Mode 18. SwiftUI Architecture 19. The Anatomy of a Basic SwiftUI Project 20. Creating Custom Views with SwiftUI 21. SwiftUI Stacks and Frames 22. SwiftUI State Properties, Observable, State and Environment Objects 23. A SwiftUI Example Tutorial 24. SwiftUI Lifecycle Event Modifiers 25. SwiftUI Observable and Environment Objects – A Tutorial 26. SwiftUI Data Persistence using AppStorage and SceneStorage 27. SwiftUI Stack Alignment and Alignment Guides 28. SwiftUI Lists and Navigation 29. A SwiftUI List and Navigation Tutorial 30. An Overview of List, OutlineGroup and DisclosureGroup 31. A SwiftUI List, OutlineGroup and DisclosureGroup Tutorial 32. Building SwiftUI Grids with LazyVGrid and LazyHGrid 33. Building Tabbed and Paged Views in SwiftUI 34. Building Context Menus in SwiftUI 35. Basic SwiftUI Graphics Drawing 36. SwiftUI Animation and Transitions 37. Working with Gesture Recognizers in SwiftUI 38. Creating a Customized SwiftUI ProgressView 39. An Overview of SwiftUI DocumentGroup Scenes 40. A SwiftUI DocumentGroup Tutorial 41. An Introduction to SiriKit 42. A SwiftUI SiriKit Messaging Extension Tutorial 43. Customizing the SiriKit Intent User Interface 44. A SwiftUI SiriKit NSUserActivity Tutorial 45. An Overview of Siri Shortcut App Integration 46. A SwiftUI Siri Shortcut Tutorial 47. Building Widgets with SwiftUI and WidgetKit 48. A SwiftUI WidgetKit Tutorial 49. Supporting WidgetKit Size Families 50. A SwiftUI WidgetKit Deep Link Tutorial 51. Adding Configuration Options to a WidgetKit Widget 52. Integrating UIViews with SwiftUI 53. Integrating UIViewControllers with SwiftUI 54. Integrating SwiftUI with UIKit 55. Preparing and Submitting an iOS 14 Application to the App Store Index

47. Building Widgets with SwiftUI and WidgetKit

Introduced in iOS 14, widgets allow small amounts of app content to be displayed alongside the app icons that appear on the device home screen pages, the Today view and the macOS Notification Center. Widgets are built using SwiftUI in conjunction with the WidgetKit Framework.

The focus of this chapter is to provide a high level outline of the various components that make up a widget before exploring widget creation in practical terms in the chapters that follow.

47.1 An Overview of Widgets

Widgets are intended to provide users with “at a glance” views of important, time sensitive information relating to your app. When a widget is tapped by the user, the corresponding app is launched, taking the user to a specific screen where more detailed information may be presented. Widgets are intended to display information which updates based on a timeline, ensuring that only the latest information is displayed to the user. A single app can have multiple widgets displaying different information.

Widgets are available in three size families (small, medium and large), of which at least one size must be supported by the widget, and can be implemented such that the information displayed is customizable by the user.

Widgets are selected from the widget gallery and positioned by the user on the device home screens. To conserve screen space, iOS allows widgets to be stacked, providing the user the ability to flip through each widget in the...

47.2 The Widget Extension

A widget is created by adding a widget extension to an existing app. A widget extension consists of a Swift file, an optional intent definition file (required if the widget is to be user configurable), an asset catalog and an Info.plist file.

The widget itself is declared as a structure conforming to the Widget protocol, and it is within this declaration that the basic configuration of the widget is declared. The body of a typical widget declaration will include the following items:

Widget kind – Identifies the widget within the project. This can be any String value that uniquely identifies the widget within the project.

Widget Configuration – A declaration which conforms to the WidgetConfiguration protocol. This includes a reference to the provider of the timeline containing the information to be displayed, the widget display name and description, and the size families supported by the widget. WidgetKit supports two...

47.3 Widget Configuration Types

When creating a widget, the choice needs to be made as to whether it should be created using the static or intent configuration model. These two options can be summarized as follows:

Intent Configuration – Used when it makes sense for the user to be able to configure aspects of the widget. For example, allowing the user to select the news publications from which headlines are to be displayed within the widget.

Static Configuration – Used when the widget does not have any user configurable properties.

When the Intent Configuration option is used, the configuration options to be presented to the user are declared within a SiriKit intent definition file.

The following is an example widget entry containing a static configuration designed to support both small and medium size families:

@main

struct SimpleWidget: Widget {

    private let kind: String = "SimpleWidget"

 ...

47.4 Widget Entry View

The widget entry view is simply a SwiftUI View declaration containing the layout to be displayed by the widget. Conditional logic (for example if or switch statements based on the widgetFamily environment property) can be used to present different layouts subject to the prevailing size family.

With the exception of tapping to open the corresponding app, widgets are non-interactive. As such, the entry view will typically consist of display-only views (in other words no buttons, sliders or toggles).

When WidgetKit creates an instance of the entry view, it passes it a widget timeline entry containing the data to be displayed on the views that make up the layout. The following view declaration is designed to display city name and temperature values:

struct SimpleWidgetEntryView : View {

    var entry: Provider.Entry

 

    var body: some View {

        VStack...

47.5 Widget Timeline Entries

The purpose of a widget is to display different information at specific points in time. The widget for a calendar app, for example, might change throughout the day to display the user’s next upcoming appointment. The content to be displayed at each point in the timeline is contained within widget entry objects conforming to the TimelineEntry protocol. Each entry must, at a minimum, include a Date object defining the point in the timeline at which the data in the entry is to be displayed, together with any data that is needed to fully populate the widget entry view at the specified time. The following is an example of a timeline entry declaration designed for use with the above entry view:

struct WeatherEntry: TimelineEntry {

    var date: Date

    let city: String

    let temperature: Int

}

If necessary, the Date object can simply be a placeholder to be updated with the...

47.6 Widget Timeline

The widget timeline is simply an array of widget entries that defines the points in time that the widget is to be updated, together with the content to be displayed at each time point. Timelines are constructed and returned to WidgetKit by a widget provider.

47.7 Widget Provider

The widget provider is responsible for providing the content that is to be displayed on the widget and must be implemented to conform to the TimelineProvider protocol. At a minimum, it must implement the following methods:

getSnapshot() – The getSnapshot() method of the provider will be called by WidgetKit when a single, populated widget timeline entry is required. This snapshot is used within the widget gallery to show an example of how the widget would appear if the user added it to the device. Since real data may not be available at the point that the user is browsing the widget gallery, the entry returned should typically be populated with sample data.

getTimeline() - This method is responsible for assembling and returning a Timeline instance containing the array of widget timeline entries that define how and when the widget content is to be updated together with an optional reload policy value.

The following code excerpt declares...

47.8 Reload Policy

When a widget is displaying entries from a timeline, WidgetKit needs to know what action to take when it reaches the end of the timeline. The following predefined reload policy options are available for use when the provider returns a timeline:

atEnd – At the end of the current timeline, WidgetKit will request a new timeline from the provider. This is the default behavior if no reload policy is specified.

after(Date) – WidgetKit will request a new timeline after the specified date and time.

never – The timeline is not reloaded at the end of the timeline.

47.9 Relevance

As previously mentioned, iOS allows widgets to be placed in a stack in which only the uppermost widget is visible. While the user can scroll through the stacked widgets to decide which is to occupy the topmost position, this presents the risk that an important update may not be seen by the user in time to act on the information.

To address this issue, WidgetKit is allowed to move a widget to the top of the stack if the information it contains is considered to be of relevance to the user. This decision is based on a variety of factors such as previous behavior of the user (for example checking a bus schedule widget at the same time every day) together with a relevance score assigned by the widget to a particular timeline entry.

Relevance is declared using a TimelineEntryRelevance structure. This contains a relevancy score and a time duration for which the entry is relevant. The score can be any floating point value and is measured relative to all other timeline...

47.10 Forcing a Timeline Reload

When a widget is launched, WidgetKit requests a timeline containing the timepoints and content to display to the user. Under normal conditions, WidgetKit will not request another timeline update until the end of the timeline is reached, and then only if required by the reload policy.

Situations may commonly arise, however, where the information in a timeline needs to be updated. A user might, for example, add a new appointment to a calendar app which requires a timeline update. Fortunately, the widget can be forced to request an updated timeline by making a call to the reloadTimelines() method of the WidgetKit WidgetCenter instance, passing through the widget’s kind string value (defined in the widget configuration as outlined earlier in the chapter). For example:

WidgetCenter.shared.reloadTimelines(ofKind: "My Kind")

Alternatively, it is also possible to trigger a timeline reload for all the active widgets associated with an...

47.11 Widget Sizes

As previously discussed, widgets can be displayed in small, medium and large sizes. The widget declares which sizes it supports by applying the supportedFamilies() modifier to the widget configuration as follows:

@main

struct SimpleWidget: Widget {

    private let kind: String = "SimpleWidget"

 

    public var body: some WidgetConfiguration {

        IntentConfiguration(kind: kind,

             intent: LocationSelectionIntent.self, provider: Provider(),

               placeholder: PlaceholderView()) { entry in

            SimpleWidgetEntryView(entry: entry)

        }

      ...

47.12 Widget Placeholder

As previously mentioned, the widget extension must provide a placeholder. This is the view which is displayed to the user while the widget is initializing and takes the form of the widget entry view without any data or information. Consider the following example widget:

Figure 47-2

The above example, of course, shows the widget running after it has received timeline data to be displayed. During initialization, however, the placeholder view resembling Figure 47-3 would be expected to be displayed:

Figure 47-3

Fortunately, SwiftUI includes the redacted(reason:) modifier which may be applied to an instance of the widget entry view to act as a placeholder. The following is an example of a placeholder view declaration for a widget extension using the redacted() modifier (note that the reason is set to placeholder):

struct PlaceholderView : View {

    var body: some View {

       ...

47.13 Summary

Introduced in iOS 14, widgets allow apps to present important information to the user directly on the device home screen without the need to launch the app. Widgets are implemented using the WidgetKit Framework and take the form of extensions added to the main app. Widgets are driven by timelines which control the information to be displayed to the user and when it is to appear. Widgets can support small, medium and large formats and may be designed to be configurable by the user. When adding widgets to the home screen, the user has the option to place them into a stack. By adjusting the relevance of a timeline entry, a widget can increase the chances of being moved to the top of the stack.

lock icon The rest of the chapter is locked
You have been reading a chapter from
SwiftUI Essentials – iOS 14 Edition
Published in: May 2021 Publisher: Packt ISBN-13: 9781801813228
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at £13.99/month. Cancel anytime}