DEV Community

Cover image for Build a SwiftUI PreviewProvider for UIKit Views
Emad Beyrami
Emad Beyrami

Posted on

Build a SwiftUI PreviewProvider for UIKit Views

Build a SwiftUI PreviewProvider for UIKit Views

A simple way to see your UIKit ViewController changes instantly — live and on-demand

Have you ever tried the SwiftUI? Haven’t you found it so delightful and easy to work with?

However, in UIKit views, if you are prototyping a design in your codebase, you have to recompile and build your project every time to see the results in the simulator. But in SwiftUI it’s so pleasant to view changes on-demand without rebuilding.

What if we can do that something similar to it for our UIKit Components? Like previewing or hot reloading the UIKit changes immediately without the time-consuming build and compile process.

Essentially, we’re looking to create a live preview system for our UIKit views using SwiftUI.


There are many ways to make this process easier such as simple annotations like @IBDesignable, @IBInspectable and etc.

But if you have experience using these sometimes it gets buggy and causes some compile errors for rational reasons and sometimes it’s not the best approach.

So in this article, you will learn a new and way simpler way to see your changes instantly. if you used SwiftUI you already know it but we add a little trick to it so it will work with UIKit.

SwiftUI: PreviewProvider

PreviewProvider is a protocol type that produces view previews in Xcode. It contains an associated type called Previews which is of type View. View is a SwiftUI view that we’ll return for the PreviewProvider to display — we’ll see this later.

After creating an object which is conforming to this protocol, we’ll pass the view we want to see in our preview. It’ll automatically pop up a split view like the picture below.

Image description

If the preview doesn’t load, worry not: simply use the below keyboard shortcut to see the reset the live preview:

⌘ + ⌥ + Return (Command + option + Return)

Note: Make sure to click on the resume button that appears in the upright corner of the preview content if you won’t see that it means it is working and showing you the live content.

UIKit: PreviewProvider

So now that we know about the PreviewProvider and how it works in SwiftUI, how can we achieve this in UIKit?

The answer is simple: We have to convert our UIKit codebase into something that SwiftUI understands and use the SwiftUI PreviewProvider to see the live simulation of the content. Any guesses how?

How to convert UIKit content to SwiftUI Content?

It is way easier than you think. Don’t make it complicated. All we need is the popular UIViewControllerRepresentable protocol.

UIViewControllerRepresentable acts as a bridge to help convert the UIViewController to SwiftUI view. Have you guessed what are we planning to do yet?

Implementation

Now that we know about UIViewControllerRepresentable and PreviewProvider in SwiftUI, Let’s get our hands dirty and use them in a practical way.

UIKit Controller

Let’s create a simple UIKit controller (UIViewController) which contains some UI modifications:

class ViewController: UIViewController {

    @IBOutlet var imageView: UIImageView!
    @IBOutlet var titleLabel: UILabel!
    @IBOutlet var confirmBtn: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        setupView()
    }

    private func setupView() {
        imageView.layer.cornerRadius = imageView.frame.height / 2
        imageView.clipsToBounds = true
        imageView.layer.borderWidth = 1
        imageView.layer.borderColor = UIColor.red.cgColor

        titleLabel.text = "This is a test ViewController to see if we can use swiftUI previews for UIKit Controllers"

        confirmBtn.setTitle("Confirm", for: .normal)
        confirmBtn.backgroundColor = .cyan
        confirmBtn.clipsToBounds = true
        confirmBtn.layer.borderWidth = 1
        confirmBtn.layer.borderColor = UIColor.blue.cgColor
        confirmBtn.layer.cornerRadius =  20
    }
 }
Enter fullscreen mode Exit fullscreen mode

If we run this ViewController you will see something like this:

Image description

Now let's create a SwiftUI Preview. Any changes we’ll make in the UIKit UI could be simply displayed in real-time and we won’t have to build and compile like earlier.

Convert this UIViewController to SwiftUI Controller

We simply make an object from our controller which is conforming to UIViewControllerRepresentable to make it readable for SwiftUI.

import Foundation

#if canImport(SwiftUI) && DEBUG
import SwiftUI

struct ViewControllerRepresentable: UIViewControllerRepresentable {

    func makeUIViewController(context: Context) -> some UIViewController {
        return UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()!
    }

    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {

    }
}
#endif
Enter fullscreen mode Exit fullscreen mode

In the code above:

  • canImport(SwiftUI) is used to ensure it will compile only for the iOS versions which support SwiftUI .

  • DEBUG makes sure it is running in our debug environment only.
    Inside the MakeUIViewController(context: Context) function, you should simply instantiate the Controller you want to see in previews.
    Here I just instantiated my Main Storyboard.

Preview our UIViewController using PreviewProvider

Now that we have the UIViewController and have already converted it to SwiftUI Controller we just have to add a few lines of code for our PreviewProvider.

Add the following lines of code before the #endif:

struct ViewController_Preview: PreviewProvider {
    static var previews: some View {
         ViewControllerRepresentable()    
    }
}
Enter fullscreen mode Exit fullscreen mode

The full code should look like this:

import Foundation

#if canImport(SwiftUI) && DEBUG
import SwiftUI

struct ViewControllerRepresentable: UIViewControllerRepresentable {

    func makeUIViewController(context: Context) -> some UIViewController {
        return UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()!
    }

    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {

    }
}

struct ViewController_Preview: PreviewProvider {
    static var previews: some View {
        ViewControllerRepresentable()
    }
}
#endif
Enter fullscreen mode Exit fullscreen mode

Now that we have the full codebase, you can see the live preview of the UIKit UIViewController on-demand. Try modifying the UI slightly and notice the instant results. Say goodbye to the time-consuming building process.

Image description

That’s all for now. Thanks for reading. You can check the full source code below:

SwiftUI preview provider for UIKit

A simple way to see your UIKit ViewController changes live and on-demand.

This is a practical project for my article SwiftUI preview provider for UIKit it is usefull. read it. :)

Introduction

Have you ever tried the SwiftUI haven’t you found it so delightful and easy to work with In UIKit views, if you are working on a piece of design that is mostly working with your codebase and you have to check it every once in a while to make sure your code makes the UI design you are trying to make; So every now and then you compile and build your code into the simulator to check your code result but in SwiftUI you can see the changes you made on-demand without having to wait for your project to build and compile What if we can use that or something similar to it…

Buy me a coffee ☕️:

Donate

favicon paypal.com

Refrences:

My Medium:

Discussion (0)