Xcode Previews speed up app UI development and testing

Laura Carvalho
ArcTouch
Published in
7 min readMay 18, 2022

At WWDC in 2019, Apple introduced a powerful new way to create user interfaces for their iOS, iPadOS and macOS platforms: SwiftUI. This allows iOS developers to build user interfaces in a state-driven declarative style. As Apple states, it’s a modern and faster way to design UI.

Along with all the exciting changes Apple added with SwiftUI, one specific item really stood out: Xcode Previews.

As a more visual thinker, I’ve always liked Storyboards because I could see the user interface as I was building it (regardless of the extra build time and merge issues when working in a big team). Using ViewCode was hard at the beginning without having a preview of what I was building. With regular use I improved, but it was still taking too long to see the screen being built when making trivial changes like the background color or adding some button padding. So I was very happy when I saw that Apple combined the best features of the two worlds into Xcode Previews!

What is the Xcode Preview tool?

Xcode Preview is a tool that displays a preview of the view’s content that stays in sync with changes to the view’s code. It provides a real representation of the UI you’re developing showed in a canvas next to your code.

To use the Xcode’s canvas, you need to make your view conform to the PreviewProvider protocol and Xcode will take care of the rest:

it will statically discover preview providers in your project and generates previews for any providers currently open in the source editor. Xcode generates the preview using the current run destination as a hint for which device to display. (PreviewProvider doc)

Why Xcode Preview is cool?

Since it’s a tool to display a real presentation of what is in your code, you can easily change the view’s code and see those changes reflected in the canvas. This makes the view always visible and editable at all times.

This reduces the time to get UI feedback on code changes. You can also speed up development through Xcode Preview by quickly trying all different possible user configurations like dark mode, localization, larger fonts, portrait/landscape orientation, and different device size without the need to run the code every time to see each configuration.

The PreviewProvider Protocol

Xcode knows what view and what file you are currently working on at all times, so it uses Swift’s dynamic replacement feature to compile just that file and inject that implementation back into your live preview.

All you need to do is implement a small type that conforms to a PreviewProvider protocol, which is a part of a SwiftUI framework. This type is the one responsible for producing the view previews and the only required property for this protocol is the `previews` variable. The return of this variable is completely up to the developer, as long it is a view.

Once the previews variable is implemented, Xcode detects its provider and generates a preview of the implementation using the current run destination (the device we select to run our code on) as a hint for which device to display in the Canvas.

When you create a new SwiftUI View, Xcode automatically inserts a preview structure at the bottom of the file, like this:

import SwiftUIstruct HelloWorldView: View {
var body: some View {
Text(“Hello, World!”)
}
}
struct HelloWorldView_Previews: PreviewProvider {
static var previews: some View {
HelloWorldView()
}
}

Another way to have this preview boilerplate added to your code is using the menu Editor > Create Preview option. However, this option will only be available to you if the selected file has imported SwiftUI.

Using Xcode Previews to speed up UI Development

Xcode Previews has modifiers which help speed up UI development and testing. Here’s some of the favorites that our iOS developers use every day.

Color Scheme

Starting on iOS 13, users now can choose to adopt a dark system-wide appearance called Dark Mode. Since then most of our apps are designed for two kinds of color schemes: light and dark mode. With previews, we can develop (and see) our views in both schemes at the same time inside the Canvas by using the .preferredColorScheme modifier.

The Light Mode is the default color scheme.

Screenshot of Xcode environment with a SwiftUI view presenting a Hello Word text and using the preferredColorScheme modifier
The Xcode Preview color scheme modifier shows your UI in either dark or light mode.

ps: The previewLayout modifier is a very helpful one when you want to limit the size of the view used in the preview. If you don’t use it, Xcode will use the current run destination of our app. previewLayout has 3 options:
- sizeThatFits: fits the preview to the size of your content
- fixedSize(width: .., height: ..): display a fixed size, in which you define its width and height, to display our content
- device: shows the preview using the device set as the run destination

Portrait/Landscape

Another cool modifier that allows us to see our view being built in different interface orientations is the previewInterfaceOrientation. This modifier accepts the 4 available values. Preview always uses Portrait as its default interface orientation.

Screenshot of Xcode environment with a SwiftUI view presenting a Hello Word view and using the previewInterfaceOrientation modifier
The Xcode Preview orientation modifier shows your UI in either portrait or landscape.

This is a much faster way to see your view in multiple orientations versus having to run your code and rotate the simulator or device.

Multiple Devices

You can also save up some developing/running time using the previewDevice to see the views on different devices with different screen sizes. Xcode will try to use the device set in the run destination, but you can also define your own device to be used by the Preview.

previewDevice modifier receives a PreviewDevice object as a parameter. The PreviewDevice object receives a String as a parameter which represents the name of the simulator in the list of simulators.

For example, if you want to see a preview in an iPhone 13 mini you declare a PreviewDevice(rawValue: “iPhone 13 mini”). Xcode handles the rest for you. There’s no limit to creating previews, so you can add as many different device previews as you want.

Screenshot of Xcode environment with a SwiftUI view presenting a Hello Word view and using the previewDevice modifier. In de Canvas there is an iPhone 13 simulator and an iPod 7th gen simulator.
The Xcode Preview device preview modifier shows your UI in various devices and screen sizes.

Pin Previews

One of the great SwiftUI highlights is how easy it is to create small view components and compose them to form a larger view. This helps reuse components and makes it easier to define a design system for apps.

Let’s say you are working on a view that is composed of other views. You need to change something in one of those views and would like to see this change right away on the complete screen. Of course, you could go to the view’s file, edit it, and then come back to the composing screen, but there’s a better way.

Inside the Canvas, there is a Pin Preview button located at the bottom left corner. It pins the current preview to the Canvas. As you make changes, you’ll see them updated in the view’s preview and the pinned preview.

Screenshot of Xcode environment with a SwiftUI view presenting a Hello Word view. There is also a green circle at the left bottom corner of the Canvas, showing where the Pin button is located.
The Pin Preview button in Xcode pins your preview to the Canvas.

UIKit and Previews

Although the PreviewProvider protocol is part of the SwiftUI framework, it doesn’t mean that it only works with SwiftUI code. In order to make this tool available to UIKit views as well, there are two other protocols designed to bridge the differences between UIKit and SwiftUI: UIViewRepresentable and UIViewControllerRepresentable.

Including those protocols in UIKit elements converts the code into something that SwiftUI understands and is able to simulate in the preview. If you have a UIView you’ll have to create a struct that implements UIViewRepresentable. Use UIViewControllerRepresentable if you are working with view controllers.

Here’s an example of the UIViewRepresentable implementation, but for a UIViewControllerRepresentable implementation is essentially the same thing.

The BadgeView example below contains a globe icon from SF Symbols and a Hello World label. The components are positioned using autolayout. To make BadgeView visible to SwiftUI and therefore to Previews, you need to implement UIViewRepresentable.

Since views in SwiftUI are structs, declare a struct to implement the protocol.

struct BadgeViewRepresentable: UIViewRepresentable {
func makeUIView(context: Context) -> BadgeView {
return BadgeView(frame: CGRect(x: 0,
y: 0,
width: 100,
height: 50))
}

func updateUIView(_ uiView: BadgeView, context: Context) {}
}

makeUIView and updateUIView need to be declared in order to make it compilable. Since you are only targeting the previews, you can leave updateUIView empty. The other method is the one responsible to connect your UIKit code available for SwiftUI. Notice that the return of makeUIView is the UIKit view, so just return your UIKit view here and you’re good to continue.

Once UIViewRepresentable is implemented it is time to instantiate the preview part.

struct BadgeViewRepresentable_Previews: PreviewProvider {
static var previews: some View {
BadgeViewRepresentable()
.previewLayout(.sizeThatFits)
}
}

The code here is exactly the same as you’ll see in SwiftUI views. The only key is that the view you need to use here is the struct that implements UIViewRepresentable, which in this case is BadgeViewRepresentable().

You should now see your UIKit view in the Canvas

Screenshot of Xcode environment with a view coded using Autolayout but being shown at the Canvas, using the Preview tool
Example of how to show UIKit items in the Xcode Preview canvas.

Now you have a good understanding of how Xcode Previews help speed up app UI development and testing. If you need any additional help with your app development projects ArcTouch offers expert app design, development, QA and product management services. Contact us to learn more.

--

--