SwiftUI- Interfacing with UIKit



In some situations, you might need to integrate UIKit components or features into a SwiftUI application. SwiftUI provides mechanisms to make it possible to use UIKit components when you need to, while still benefiting from SwiftUIs declarative nature for the rest of your UI.

To interface with UIKit from SwiftUI, you'll need to use UIViewRepresentable and UIViewControllerRepresentable protocols. These protocols let you wrap UIKit components (like views or view controllers) and embed them within SwiftUI.

  • UIViewRepresentable

  • UIViewControllerRepresentable

UIViewRepresentable

The UIViewRepresentable protocol is used when you want to wrap UIKit views (like UIButton, UILabel, UISlider, UITextField, etc.) into SwiftUI views. This is useful when you need a specific UIKit view that doesnt have a direct SwiftUI equivalent.

Example

The following SwiftUI program is used for UIViewRepresentable.

import SwiftUI
import UIKit

// Step 1: Create a custom SwiftUI view that conforms to UIViewRepresentable
struct CustomButton: UIViewRepresentable {
   var title: String
   var action: () -> Void
   
   // Create the UIKit view
   func makeUIView(context: Context) -> UIButton {
      let button = UIButton(type: .system)
      button.setTitle(title, for: .normal)
      button.addTarget(context.coordinator, action: #selector(Coordinator.buttonTapped), for: .touchUpInside)
      return button
   }   
   // Update the UIKit view with new data
   func updateUIView(_ uiView: UIButton, context: Context) {
      uiView.setTitle(title, for: .normal)
   }   
   // Step 2: Create a Coordinator class to manage interaction
   class Coordinator: NSObject {
      var parent: CustomButton      
      init(parent: CustomButton) {
         self.parent = parent
      }      
      @objc func buttonTapped() {
         parent.action()  // Perform the action when the button is tapped
      }
   }   
   // Create a coordinator to handle button actions
   func makeCoordinator() -> Coordinator {
      return Coordinator(parent: self)
   }
}
// Step 3: Use the custom UIKit button in your SwiftUI view
struct ContentView: View {
   var body: some View {
      VStack {
         CustomButton(title: "Tap me!") {
            print("Button was tapped!")
         }.padding()
      }
   }
}
@main
struct MyApp: App {
   var body: some Scene {
      WindowGroup {
         ContentView()
      }
   }
}

Output

Interfacing with UIKit

UIViewControllerRepresentable

The UIViewControllerRepresentable protocol is used to wrap UIKit view controllers (e.g., UIImagePickerController, UIActivityViewController, UIPageViewController) into SwiftUI.

Example

The following SwiftUI program is used for UIViewControllerRepresentable.

import SwiftUI
import UIKit

// Step 1: Create a custom SwiftUI view that conforms to UIViewControllerRepresentable
struct ImagePicker: UIViewControllerRepresentable {
   @Binding var selectedImage: UIImage?
   @Binding var isPresented: Bool
   
   // Create the UIKit view controller
   func makeUIViewController(context: Context) -> UIImagePickerController {
      let picker = UIImagePickerController()
      picker.delegate = context.coordinator
      return picker
   }   
   // Update the UIKit view controller with new data
   func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {
      // Nothing to update in this case
   }   
   // Step 2: Create a Coordinator class to manage interaction
   class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
      var parent: ImagePicker
      
      init(parent: ImagePicker) {
         self.parent = parent
      }      
      // Handle image picking
      func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
         if let image = info[.originalImage] as? UIImage {
            parent.selectedImage = image
         }
         parent.isPresented = false
      }      
      // Handle cancellation
      func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
         parent.isPresented = false
      }
   }   
   // Create the coordinator
   func makeCoordinator() -> Coordinator {
      return Coordinator(parent: self)
   }
}
// Step 3: Use the custom Image Picker in your SwiftUI view
struct ContentView: View {
   @State private var isImagePickerPresented = false
   @State private var selectedImage: UIImage?
   
   var body: some View {
      VStack {
         if let selectedImage = selectedImage {
            Image(uiImage: selectedImage)
               .resizable()
               .scaledToFit()
               .frame(width: 200, height: 200)
         }
         
         Button("Pick an Image") {
            isImagePickerPresented.toggle()
         }.imagePicker(isPresented: $isImagePickerPresented, selectedImage: $selectedImage)  // Custom ImagePicker
      }
   }
}
@main
struct MyApp: App {
   var body: some Scene {
      WindowGroup {
         ContentView()
      }
   }
}

Output

Interfacing with UIKit
Advertisements