How to preview UIView in Xcode Previews

⋅ 6 min read ⋅ Xcode Xcode Previews

Table of Contents

What is Xcode Preview

Apple introduces Xcode Previews and SwiftUI in WWDC 2019 (Xcode 11 and iOS 13).

You can see how SwiftUI views look in real-time, and you can interact with it without running your app using Xcode Previews.

Here is an example of Xcode Previews.

Xcode Previews.
Xcode Previews.

As you can see, once we add a new code, the update reflects on the preview.

And you can tap a button to change the view's state.

You can easily support sarunw.com by checking out this sponsor.

Sponsor sarunw.com and reach thousands of iOS developers.

How to use Xcode Previews with UIView

Since it was released at the same time as SwiftUI, you might not know you can use Xcode Previews with UIView.

If you use UIKit, you can preview your view using Interface Builder. But this might benefit you if you create a custom view programmatically without Storyboard or nib.

In this article, I will show you how to preview UIView using Xcode Previews.

To make your views work with Xcode previews, you need to do three things.

  1. Import SwiftUI module.
  2. Create a struct that conforms to the PreviewProvider protocol.
  3. Wrap a view into a SwiftUI view using UIViewRepresentable.
// 1
import SwiftUI
// 2
struct UIView_Preview: PreviewProvider {
// 3
static var previews: some View {
// return any UIViewRepresentable here
}
}

1 Xcode preview works hand in hand with PreviewProvider. It discovers preview providers and generates previews for us. PreviewProvider is a part of the SwiftUI module, so we need to import SwiftUI to use it.
2 We create a struct that conforms to the PreviewProvider.
3 Normally, we will return a SwiftUI view from the previews static property. But we want to preview a view here, so we need to wrap it using the UIViewRepresentable protocol.

So, we got everything ready. Let's jump to the implementation detail.

UIViewRepresentable

First, we need to convert a view into a SwiftUI view using UIViewRepresentable.

The process is straightforward. You just need to initialize your view and return it from makeUIView(). You can read more about this in detail in how to convert a view to SwiftUI.

struct SwiftUIHelloWorldView: UIViewRepresentable {
// 1
func makeUIView(context: Context) -> HelloWorldView {
return HelloWorldView()
}

func updateUIView(_ view: HelloWorldView, context: Context) {}
}

1 We initialize our view and return that view from func makeUIView(context: Context) -> HelloWorldView.

Preview Provider

After converting a view to a SwiftUI view, we are halfway done.

The only thing left is to use it for preview.

import SwiftUI

struct HelloWorldView_Previews: PreviewProvider {
static var previews: some View {
SwiftUIHelloWorldView()
}
}

Here is the result.

Preview a UIView.
Preview a UIView.

Caveat

There is a limitation when previewing UIView using UIViewRepresentable.

It doesn't work very well with .previewLayout(.sizeThatFits). UIViewRepresentable will always render using the currently selected device size.

This example won't show the SwiftUIHelloWorldView intrinsic size but will render the same size as a device.

struct HelloWorldView_Previews: PreviewProvider {
static var previews: some View {
SwiftUIHelloWorldView()
.previewLayout(.sizeThatFits)
}
}
Implicit intrinsic content size won't work in Xcode Preview.
Implicit intrinsic content size won't work in Xcode Preview.

You can easily support sarunw.com by checking out this sponsor.

Sponsor sarunw.com and reach thousands of iOS developers.

Helpers

Having to create UIViewRepresentable for every view you want to preview is cumbersome.

If you have a lot of view controller classes, you should come up with a helper method for easily wrapping your view into UIViewRepresentable.

There are many ways to tackle this problem. I can give you one example here.

import SwiftUI
import UIKit

// 1
struct PreviewContainer<T: UIView>: UIViewRepresentable {
// 2
let view: T

// 3
init(_ viewBuilder: @escaping () -> T) {
view = viewBuilder()
}

// MARK: - UIViewRepresentable
func makeUIView(context: Context) -> T {
// 4
return view
}

// 5
func updateUIView(_ view: T, context: Context) {
view.setContentHuggingPriority(.defaultHigh, for: .horizontal)
view.setContentHuggingPriority(.defaultHigh, for: .vertical)
}
}

1 I create a generic struct that can accept any type that is a subclass of UIView. We make this struct conform to UIViewRepresentable since it will act as our SwiftUI view wrapper for our view.
2 We define an instance property that will hold a view.
3 We create an initializer that accepts a closure that returns a view. We execute it to get the resulting view.
4 We return the resulting view from makeUIView().
5 We set content hugging priority to .defaultHigh to mitigate the limitation mentioned in the previous section.

This is how we use PreviewContainer.

import UIKit
import SwiftUI

class HelloWorldView: UIView {
...
}

struct HelloWorldView_Previews: PreviewProvider {
static var previews: some View {
// 1
PreviewContainer {
return HelloWorldView()
}
}
}

1 We provide a closure that returns a view as an argument for PreviewContainer.

We can use this PreviewContainer to preview any view without a need to recreate UIViewRepresentable.

Preview a view in Xcode Previews.
Preview a view in Xcode Previews.

Read more article about Xcode, Xcode Previews, or see all available topic

Enjoy the read?

If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.

Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.

If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.

Become a patron Buy me a coffee Tweet Share
Previous
SwiftUI Button can't tap on a background

Learn how to make the whole area of a button tappable.

Next
Xcode Previews with UIKit and AppKit in Xcode 15

Learn about the Xcode Previews improvement in Xcode 15.

← Home