Integrating UIKit with SwiftUI
Integrating UIKit with SwiftUI can be a powerful technique, allowing you to leverage the mature components and features of UIKit within the modern, declarative framework of SwiftUI. Here, we’ll explore how to integrate these two frameworks with a practical example.
Introduction
SwiftUI is a declarative framework that lets you build beautiful UIs with less code. However, for some advanced use-cases, you might still need to use UIKit. Integrating SwiftUI with UIKit allows you to reuse existing UIKit components and gradually migrate to SwiftUI.
Basic Concepts
There are two primary ways to integrate SwiftUI and UIKit:
- UIHostingController: Embeds a SwiftUI view into a UIKit view hierarchy.
- UIViewRepresentable/UIViewControllerRepresentable: Provides wrappers to use UIKit views and view controllers within SwiftUI.
Example Project: Integrating a UIKit Map View in SwiftUI
Let’s look at a simple example where we integrate an MKMapView
(MapKit) into SwiftUI.
Step 1: Create a SwiftUI Project
Create a new SwiftUI project in Xcode. After the project is created, open the ContentView.swift
file and add new content.
Step 2: Create a UIViewRepresentable for MKMapView
Create a wrapper by adopting the UIViewRepresentable
protocol to integrate MKMapView
into SwiftUI.
import SwiftUI
import MapKit
struct MapView: UIViewRepresentable {
func makeUIView(context: Context) -> MKMapView {
MKMapView(frame: .zero)
}
func updateUIView(_ uiView: MKMapView, context: Context) {
let coordinate = CLLocationCoordinate2D(
latitude: 37.7749, longitude: -122.4194)
let span = MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
let region = MKCoordinateRegion(center: coordinate, span: span)
uiView.setRegion(region, animated: true)
}
}
Step 3: Use MapView in SwiftUI
Now, use MapView
in ContentView
.
struct ContentView: View {
var body: some View {
VStack {
Text("Map View in SwiftUI")
.font(.largeTitle)
.padding()
MapView()
.edgesIgnoringSafeArea(.all)
}
}
}
Step 4: Run the Project
Run the project, and you should see a Map View within SwiftUI displaying the San Francisco location.
Using UIViewControllerRepresentable
Now let’s integrate a UIViewController
. For this example, we'll use a UIKit-based photo picker.
Step 1: Create a UIViewControllerRepresentable for UIImagePickerController
Create a wrapper by adopting the UIViewControllerRepresentable
protocol to integrate UIImagePickerController
into SwiftUI.
import SwiftUI
import UIKit
struct ImagePicker: UIViewControllerRepresentable {
@Binding var image: UIImage?
@Environment(\.presentationMode) var presentationMode
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
var parent: ImagePicker
init(parent: ImagePicker) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let uiImage = info[.originalImage] as? UIImage {
parent.image = uiImage
}
parent.presentationMode.wrappedValue.dismiss()
}
}
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
func makeUIViewController(context: Context) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.delegate = context.coordinator
return picker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {}
}
Step 2: Use ImagePicker in SwiftUI
Use ImagePicker
in ContentView
and add functionality to pick an image.
struct ContentView: View {
@State private var image: UIImage?
@State private var isImagePickerPresented = false
var body: some View {
VStack {
Text("Select an Image")
.font(.largeTitle)
.padding()
if let image = image {
Image(uiImage: image)
.resizable()
.scaledToFit()
.frame(width: 300, height: 300)
} else {
Rectangle()
.fill(Color.gray)
.frame(width: 300, height: 300)
}
Button(action: {
isImagePickerPresented.toggle()
}) {
Text("Pick Image")
.font(.headline)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
.sheet(isPresented: $isImagePickerPresented) {
ImagePicker(image: $image)
}
}
}
}
Step 3: Run the Project
Run the project, and you should see image picker functionality within SwiftUI.
Conclusion
Integrating SwiftUI and UIKit allows you to leverage the best features of both frameworks. This approach lets you reuse existing UIKit code and gradually migrate to SwiftUI. By using these techniques, you can make your apps more powerful and flexible.
I hope this article helps you in integrating UIKit with SwiftUI. Happy coding!