Using a SwiftUI View in a UIKit App
By the end of this tutorial, you will be able to programmatically integrate a SwiftUI View into a UIKit app.
The SwiftUI framework was unveiled in 2019 and in just a few years has proven to be impactful in the developer community. But it is also true that UIKit has been around since 2008! Especially if you have been a developer for a few years you will have Apps developed using UIKit. Why not use all that SwiftUI has to offer to give your apps a makeover?
Given the benefits of using SwiftUI for future development, it will be a common requirement to integrate the new SwiftUI app functionality with the existing project codebase. Fortunately, this integration can be achieved easily using UIHostingController. Let's have a look.
UIHostingController
The hosting controller is compatible with UIKit since it is a subclass of UIViewController
. The purpose of the UIHostingController
is to enclose a SwiftUI view so that it can be integrated into an existing UIKit based project.
Using a HostingViewController
, a SwiftUI view can be treated either as an entire scene (occupying the full screen) or as an individual component within an existing UIKit scene.
In this tutorial, we will walk through how to integrate a SwiftUI view by treating it as an entire scene.
Starting point and goal
Our starting point is an essential UIKit based app using the Storyboard. The main ViewController
contains a simple UIImage
a UILabel
and a UIButton
. The only component we are going to really use in this tutorial is the filled UIButton
titled “Go to SwiftUI View”.
The goal is to navigate from the ViewController
to an animated View developed in SwiftUI when tapping on the UIButton
just described.
In the animated image below you can see what we will create together at the end.
Create the integration programmatically
Let’s move the ViewController.swift file controlling the button we are interested in.
1. First of all, if you are using a Storyboard for your app, create a @IBAction
for your UIButton
.
class ViewController: UIViewController {
// 1. Create the IBAction outlet
@IBAction func goToSwiftUIView(_ sender: Any) {
// add action
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
2. Create a UIHostingController
named swiftUIController
using the SwiftUIView()
as a root view so that it can be integrated into our UIKit based project.
class ViewController: UIViewController {
// 2. Create a UIHostingController
let swiftUIController = UIHostingController(rootView: SwiftUIView())
// 1. Create the IBAction outlet
@IBAction func goToSwiftUIView(_ sender: Any) {
// add action
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
3. Now that we have a hosting controller, we can use it as we would for any other view controller. In this example, we are pushing the swiftUIController
using the navigationController
that embeds the ViewController
.
class ViewController: UIViewController {
// 2. Create a UIHostingController
let swiftUIController = UIHostingController(rootView: SwiftUIView())
// 1. Create the IBAction outlet
@IBAction func goToSwiftUIView(_ sender: Any) {
// 3. Push the UIHostingController
navigationController?.pushViewController(swiftUIController, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Create the integration using the Storyboard and a Segue Outlet
1. Add a UIHostingController in the Storyboard
Open the Library by clicking on the +
button in Xcode’s top right corner. Search for UIHostingController
and drag and drop it to the Storyboard.
2. Create a Segue in the Storyboard
To create a Segue control-drag (hold down the ctrl key and drag the element) from the UIButton
in the main ViewController
to the UIHostingController
we have just added.
3. Create a Segue Outlet
Using the Assistant editor, which allows you to see the Storyboard and code at the same time, we create a Segue Outlet by control-dragging from the Storyboard arrow (connecting the two ViewControllers) to the ViewController
class. We have just created a @IBSegueAction
and we named it segueToSwiftUIView
.
4. Implement the @IBSegueAction
Move to the ViewController.swift
and let’s modify the placeholder Xcode added for us with the creation of the @IBSegueAction
.
We are going to return a UIHostingController
that uses the SwiftUIView
as a root view so that it can be integrated into our UIKit based project. coder
is an abstract class that serves as the basis for objects that enable archiving and distribution of other objects.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
// 3. Create a Segue Outlet
@IBSegueAction func segueToSwiftUIView(_ coder: NSCoder) -> UIViewController? {
// 4. Implement the @IBSegueAction
return UIHostingController(coder: coder, rootView: SwiftUIView())
}
}
Your UIKit based project is now hosting an animated SwiftUI View! Creating an animation is just one of the possible examples where it can be convenient to use SwiftUI instead of other frameworks (like UIKit). You now have a new ace up your sleeve to speed up your legacy app development process.
Wrapping up
We have explored two different ways to integrate our SwiftUI views into a UIKit-based app. Specifically, we used our SwiftUI views as entire scenes in our app.
As next steps you could explore:
- how to pass data between a
UIViewController
and a SwiftUI View used as aUIHostingController
rootView
- How to use a SwiftUI View as an individual component using a
ContainerView
. For this you can check out the tutorial Using a SwiftUI View in a UIKit App as an individual component tutorial.