2022 EssentialsSwiftUI & UI Frameworks
WWDC22 · 26 min · Essentials / SwiftUI & UI Frameworks
Use SwiftUI with UIKit
Learn how to take advantage of the power of SwiftUI in your UIKit app. Build custom UICollectionView and UITableView cells seamlessly with SwiftUI using UIHostingConfiguration. We’ll also show you how to manage data flow between UIKit and SwiftUI components within your app. To get the most out of this session, we encourage basic familiarity with SwiftUI.
Watch at developer.apple.com ↗Code shown on screen · 15 snippets
Presenting a UIHostingController
// Presenting a UIHostingController
let heartRateView = HeartRateView() // a SwiftUI view
let hostingController = UIHostingController(rootView: heartRateView)
// Present the hosting controller modally
self.present(hostingController, animated: true) Embedding a UIHostingController
// Embedding a UIHostingController
let heartRateView = HeartRateView() // a SwiftUI view
let hostingController = UIHostingController(rootView: heartRateView)
// Add the hosting controller as a child view controller
self.addChild(hostingController)
self.view.addSubview(hostingController.view)
hostingController.didMove(toParent: self)
// Now position & size the hosting controller’s view as desired… Presenting UIHostingController as a popover
// Presenting UIHostingController as a popover
let heartRateView = HeartRateView() // a SwiftUI view
let hostingController = UIHostingController(rootView: heartRateView)
// Enable automatic preferredContentSize updates on the hosting controller
hostingController.sizingOptions = .preferredContentSize
hostingController.modalPresentationStyle = .popover
self.present(hostingController, animated: true) Passing data to SwiftUI with manual UIHostingController updates
// Passing data to SwiftUI with manual UIHostingController updates
struct HeartRateView: View {
var beatsPerMinute: Int
var body: some View {
Text("\(beatsPerMinute) BPM")
}
}
class HeartRateViewController: UIViewController {
let hostingController: UIHostingController< HeartRateView >
var beatsPerMinute: Int {
didSet { update() }
}
func update() {
hostingController.rootView = HeartRateView(beatsPerMinute: beatsPerMinute)
}
} Passing an ObservableObject to automatically update SwiftUI views
// Passing an ObservableObject to automatically update SwiftUI views
class HeartData: ObservableObject {
var beatsPerMinute: Int
init(beatsPerMinute: Int) {
self.beatsPerMinute = beatsPerMinute
}
}
struct HeartRateView: View {
var data: HeartData
var body: some View {
Text("\(data.beatsPerMinute) BPM")
}
} Passing an ObservableObject to automatically update SwiftUI views
// Passing an ObservableObject to automatically update SwiftUI views
class HeartRateViewController: UIViewController {
let data: HeartData
let hostingController: UIHostingController<HeartRateView>
init(data: HeartData) {
self.data = data
let heartRateView = HeartRateView(data: data)
self.hostingController = UIHostingController(rootView: heartRateView)
}
} UIHostingConfiguration
cell.contentConfiguration = UIHostingConfiguration {
// Start writing SwiftUI here!
} Building a custom cell using SwiftUI with UIHostingConfiguration
// Building a custom cell using SwiftUI with UIHostingConfiguration
cell.contentConfiguration = UIHostingConfiguration {
HeartRateTitleView()
}
struct HeartRateTitleView: View {
var body: some View {
HStack {
Label("Heart Rate", systemImage: "heart.fill")
.foregroundStyle(.pink)
.font(.system(.subheadline, weight: .bold))
Spacer()
Text(Date(), style: .time)
.foregroundStyle(.secondary)
.font(.footnote)
}
}
} Building a custom cell using SwiftUI with UIHostingConfiguration
// Building a custom cell using SwiftUI with UIHostingConfiguration
cell.contentConfiguration = UIHostingConfiguration {
VStack(alignment: .leading) {
HeartRateTitleView()
Spacer()
HeartRateBPMView()
}
}
struct HeartRateBPMView: View {
var body: some View {
HStack(alignment: .firstTextBaseline) {
Text("90")
.font(.system(.title, weight: .semibold))
Text("BPM")
.foregroundStyle(.secondary)
.font(.system(.subheadline, weight: .bold))
}
}
} Building a custom cell using SwiftUI with UIHostingConfiguration, with a chart!
// Building a custom cell using SwiftUI with UIHostingConfiguration
cell.contentConfiguration = UIHostingConfiguration {
VStack(alignment: .leading) {
HeartRateTitleView()
Spacer()
HStack(alignment: .bottom) {
HeartRateBPMView()
Spacer()
Chart(heartRateSamples) { sample in
LineMark(x: .value("Time", sample.time),
y: .value("BPM", sample.beatsPerMinute))
.symbol(Circle().strokeBorder(lineWidth: 2))
.foregroundStyle(.pink)
}
}
}
} Content margins
cell.contentConfiguration = UIHostingConfiguration {
HeartRateBPMView()
}
.margins(.horizontal, 16) Cell backgrounds
cell.contentConfiguration = UIHostingConfiguration {
HeartTitleView()
}
.background(.pink) List swipe actions
cell.contentConfiguration = UIHostingConfiguration {
MedicalConditionView()
.swipeActions(edge: .trailing) { … }
} Incorporating UIKit cell states
// Incorporating UIKit cell states
cell.configurationUpdateHandler = { cell, state in
cell.contentConfiguration = UIHostingConfiguration {
HStack {
HealthCategoryView()
Spacer()
if state.isSelected {
Image(systemName: "checkmark")
}
}
}
} Creating a two-way binding to data in SwiftUI
// Creating a two-way binding to data in SwiftUI
class MedicalCondition: Identifiable, ObservableObject {
let id: UUID
var text: String
}
struct MedicalConditionView: View {
var condition: MedicalCondition
var body: some View {
HStack {
Spacer()
}
}
} Resources
Related sessions
-
24 min -
17 min -
1 min -
30 min -
36 min