Apple is continuing to work to bring SwiftUI, its declarative UI framework for Swift, on a par with UIKit and AppKit. At WWDC 2021, SwiftUI got a number of new features, including extended List views, support for pull to refresh, asynchronous images, and more.
Lists are a cornerstone of iOS app design, yet it took Apple two years to add support for custom swipe actions and pull to refresh, two of the most common interaction paradigms, to SwiftUI List
.
With SwiftUI 3, custom swipe actions can be added to list items. You can add multiple buttons to support different actions, as well as designate one of those action as the default action that will be executed on a full swipe. This is how you can add swipe actions from both edges of the display:
List {
ForEach(labels) { label in
Text(label)
.swipeActions(edge: .leading) {
Button { doAction(message) } { buttonImage }
}
.swipeActions(edge: .trailing) {
Button { doAnotherAction(message) } { anotherButtonImage }
}
}
}
Similarly, you can now use the refreshable()
modifier to trigger an async operation when the user performs a standard gesture:
List(mailbox.conversations) {
ConversationCell($0)
}
.refreshable {
await mailbox.fetch()
}
Another important new feature related to lists is support for searching using the searchable
modifier. You can attach it to a NavigationView
or to a List
, and specify a label, a placement hint, and autocompletion suggestions:
List {...}.searchable("Search", text: $value, placement: .automatic) {
Text("moniker1").searchCompletion("fullValue1")
Text("moniker2").searchCompletion("fullValue2")
...
}
Other useful additions to SwiftUI lists include a few modifiers to style separators and tint colors in sections and cells, including listRowSeparatorTint
, listRowSeparator
, and listSectionSeparatorTint
.
SwiftUI 3 also brings forward support for asynchronous operations within views. In particular, the new task
modifier allows you to start an asynchronous operation when a view is first displayed:
Text(value).task { value = await asyncOp() }
task
is similar to onAppear
, but it is specifically geared to async operations. For example, when the view disappears, the async task is automatically cancelled.
Additionally, AsyncImage
makes it straightforward to display an image downloaded from a remote location. You can specify a placeholder image to display while the remote image is being downloaded and manipulate the latter in a closure, e.g. to make it resizable:
AsyncImage(url: URL(string: "https://example.com/icon.png")) { image in
image.resizable()
} placeholder: {
ProgressView()
}
.frame(width: 50, height: 50)
A non-user facing feature in SwiftUI 3 that will make developers' lives much easier is the Self._printChanges()
method that can be called from within a View's body
method. This can be used to log the name of the property that changed, thus causing a view to be re-rendered. As the underscore in its name implies, this method is not meant to be used in shipping apps.
Other useful extensions to SwiftUI include the FocusState
property wrapper, which enables managing the state of a control being focused or not; markdown support in AttributedString
and Text
classes; material background types that are meant to emulate the glass-like blurring effect produced by several kinds of materials, from ultra thin to ultra thick, on a view which appears in the background.
SwiftUI 3 is still in beta and will become available with iOS 15 and Xcode 13.
There is much more to SwiftUI 3 than can be covered here, so do not miss the What's new in SwiftUI video from WWDC 2021 if you are interested.