How do I bridge between SwiftUI and UIKit

917 Views Asked by At

I'm currently working on a project using both swiftUI and UIKit. I made a ViewController to work on, but now I want to use that as a navigation link in the original content view.

The first thing I tried was the normal

NavigationLink{
                    ViewController()
                } label: {
                    Text("XXX")
                }

but I got these two errors:

Generic struct 'NavigationLink' requires that 'ViewController' conform to 'View'

Static method 'buildBlock' requires that 'ViewController' conform to 'View'

I found this this post which said to use a struct, but that didn't work either and I got other errors too.

So how can I efficiently use my viewcontroller as a navigationlink

1

There are 1 best solutions below

0
On

You do need to wrap your view controller in a SwiftUI struct that conforms to the UIViewControllerRepresentable protocol. This allows you to use a UIKit view controller in your SwiftUI view hierarchy.

There's a very similar protocol, UIViewRepresentable, that works for UIKit views that aren't controllers - it works in almost exactly the same way.

So if your UIKit view controller is called MyViewController, we could wrap it in a Swift view that we'll call MyView. There are two methods that we have to implement:

struct MyView: UIViewControllerRepresentable {
  // autocomplete will give a return value of `some UIViewController`
  // but if you replace that with your controller's class name, it
  // makes everything clearer
  func makeUIViewController(context: Context) -> MyViewController {
    // do basic setup in here
    return MyViewController()
  }

  func updateUIViewController(
    // you have to specify your UIKit class name here too
    _ uiViewController: MyViewController,
    context: Context
  ) {
    // do the main configuration of your view controller in here,
    // especially if there's SwiftUI state you need the controller
    // to react to
    /// 
    // You don't have to do anything in this method, but you still have
    // to include it. Leave it empty if you're not configuring anything
  }
}

That is all you have to do to get a version of your controller to work within SwiftUI's view hierarchy. You have to remember to use the SwiftUI wrapper rather than your UIKit view controller directly, e.g.:

NavigationLink{
  MyView()
} label: {
  Text("XXX")
}

There's more to do if you need to pass information in to the view controller to set it up, to get it to respond to changes in your SwiftUI state, or if you want to update state based on events or actions in the controller. But that's outside the scope of your question, I think.