Using Live Preview in UIKit

Elevating UIKit Development with Live Preview: A Step-by-Step Guide

Nikhil Vinod
4 min readJan 16, 2023

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 the UIView instance that will be used in the preview.
  • updateUIView(_:context:): This method is used to update the UIView 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 ❤️

--

--