Using Live Preview in UIKit
Elevating UIKit Development with Live Preview: A Step-by-Step Guide
Since the implementation of Live Preview in Xcode, I have found it to be a highly efficient and convenient method for testing and debugging my SwiftUI code. The ability to preview my animations in real-time has dramatically reduced the development time, making it an ideal tool for my work with SwiftUI. I no longer rely on simulators or physical devices to test my code, as Live Preview offers a seamless and intuitive experience.
UIKit is a powerful tool for creating rich and interactive user interfaces. It can be difficult to quickly iterate on the design and layout of your views without building and running the app on a simulator or device. That’s where Live Preview comes in.
To use Live Preview with UIKit, we must wrap our UIViewControllers and UIViews into SwiftUI views. This can be achieved by using the protocols UIViewControllerRepresentable
and UIViewRepresentable
.
UIViewControllerRepresentable
and UIViewRepresentable
are protocols in the SwiftUI framework that allow you to represent UIViewController
or UIView
, respectively, in a SwiftUI environment. These protocols define the methods and properties needed to create and manage a UIViewController
or UIView
instance in a SwiftUI environment.
Setting up the Wrapper
We will create a new file and name it LivePreview
. We will import the SwiftUI framework and define two structs named UIViewControllerPreview
and UIViewPreview
within this file. Each conforming to UIViewControllerRepresentable
and UIViewRepresentable
respectively
UIViewControllerPreview
and UIViewPreview
are generic structs that takes a type parameter ViewController
and View
which conforms to the UIViewController
and UIView
protocol respectively.
struct UIViewControllerPreview<ViewController: UIViewController>: UIViewControllerRepresentable
struct UIViewPreview<View: UIView>: UIViewRepresentable
Understanding UIViewControllerRepresentable
The Signature of the UIViewControllerRepresentable is like below:
protocol UIViewControllerRepresentable : View where Self.Body == Never
To conform to the UIViewControllerRepresentable
protocol, a struct must implement the following methods:
makeUIViewController(context:) -> UIViewController
: This method is used to create the UIViewController instance that will be used in the preview.updateUIViewController(_:context:)
: This method is used to update the UIViewController instance when the SwiftUI view hierarchy changes.
Understanding UIViewRepresentable
The Signature of the UIViewControllerRepresentable is like below:
protocol UIViewRepresentable : View where Self.Body == Never
To conform to the UIViewRepresentable
protocol, a struct must implement the following methods:
makeUIView(context:) -> UIView
: This method is used to create theUIView
instance that will be used in the preview.updateUIView(_:context:)
: This method is used to update theUIView
instance when the SwiftUI view hierarchy changes.
By conforming to these protocols, developers can use the structs to represent a UIViewController
or UIView
in a SwiftUI environment, we can see how the UI will look and behave in a live preview. It’s important to note that these protocols are not meant to replace UIViewController
or UIView
in iOS development but rather to allow them to be used alongside SwiftUI views seamlessly.
Implementation
We will set up the mandatory function in our struct which I mentioned before like below.
struct UIViewControllerPreview<ViewController: UIViewController>: UIViewControllerRepresentable {
let viewController: ViewController
init(_ viewController: ViewController) {
self.viewController = viewController
}
func makeUIViewController(context: Context) -> ViewController {
viewController
}
func updateUIViewController(_ uiViewController: ViewController, context: Context) { }
}
struct UIViewPreview<View: UIView>: UIViewRepresentable {
let view: View
init(_ view: View) {
self.view = view
}
func makeUIView(context: Context) -> UIView {
return view
}
func updateUIView(_ view: UIView, context: Context) {
view.setContentHuggingPriority(.defaultHigh, for: .horizontal)
view.setContentHuggingPriority(.defaultHigh, for: .vertical)
}
}
To utilize the Live Preview feature in a UIKit, we will begin by importing the SwiftUI framework and creating a Preview struct that conforms to the PreviewProvider
protocol. Within this struct, we will define a variable named Previews
, which will utilize the UIViewControllerPreview
wrapper we created earlier and pass in our desired ViewController like below.
struct ViewController_Preview: PreviewProvider {
static var previews: some View {
UIViewControllerPreview(ViewController())
}
}
In this case, the name of the UIViewController
is ViewController.
Once this is set up, we can open the Canvas mode by clicking Command + Option + Return. This will open Canvas in the assistant editor window, allowing us to see a live preview of our ViewController.
As we make changes to our ViewController, such as updating the background colour of its view, like in the above gif, which I shared, we can see those changes reflected in real-time within the live preview.
In summary, by wrapping our UIKit UIViewController
in a struct that conforms to the UIViewControllerRepresentable
protocol, we can extend Live Preview to our UIViewController
, allowing for a more efficient workflow when designing and iterating on our user interface.
If you enjoyed reading this article and found it helpful, please consider giving it some claps and do follow me for more content like this in the future ❤️