Integrating UIKit with SwiftUI

Nitish Kumar
3 min readJun 16, 2024

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:

  1. UIHostingController: Embeds a SwiftUI view into a UIKit view hierarchy.
  2. 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!

--

--