SwiftUI Previews

The Ultimate Guide to SwiftUI Previews

Ix76y
5 min readJan 12, 2023

--

Since the introduction of SwiftUI Previews have been one of the biggest updates. Instead of having to start the simulator we can now create custom views and see them in the preview with the content staying up-to-date as we make changes.

The default preview that shows when we create a new SwiftUI view is already amazing as it allows us to quickly change things like the color scheme, orientation, and dynamic type. But there is so much more we can do with SwiftUI Previews that allow us to quickly test our newly create views!

Using the Canvas Device Settings to quickly check different color schemes and device orientations
Canvas Device Settings for Testing

Content

  1. Showing previews with data
  2. Creating multiple previews
  3. Customizing previews name and device type
  4. Customizing the previews size

1. Showing Previews with Data

To have some example we can work with we can use the final code from Creating an Image Card in SwiftUI displayed below:

import SwiftUI

struct ImageCard: View {
var body: some View {
VStack(alignment: .leading, spacing: 16.0) {
Image("Workout")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 240, height: 200)
cardText.padding(.horizontal, 0)
}
.background(.white)
.clipShape(RoundedRectangle(cornerRadius: 24.0))
.shadow(radius: 8.0)
}

var cardText: some View {
VStack(alignment: .leading, spacing: 4.0) {
Text("Evening Workout").font(.headline)
HStack(spacing: 4.0) {
Image(systemName: "clock.arrow.circlepath")
Text("50 min")
}.foregroundColor(.gray)
}.padding()
}
}

Currently the image card is very static and we can’t easily create multiple cards with different content. To fix this we can just introduce the image, the title, and the duration as variables and use those.

Before the preview will render we need to now pass those values to the preview:

import SwiftUI

struct ImageCard: View {
var image: String
var title: String
var time: String

var body: some View {
VStack(alignment: .leading, spacing: 16.0) {
Image(self.image) // NEW: use variable instead of name
// ...
cardText
.padding(.horizontal, 0)
}
// ...
}

var cardText: some View {
VStack(alignment: .leading, spacing: 4.0) {
Text(self.title) // NEW: use variable instead of title
// ...
HStack(spacing: 4.0) {
Image(systemName: "clock.arrow.circlepath")
Text(self.time) // NEW: use variable instead of time
}.foregroundColor(.gray)
}// ...
}
}

struct ImageCard_Previews: PreviewProvider {
static var previews: some View {
// NEW: pass variables to the preview
ImageCard(image: "Yoga", title: "Lunch-Time Yoga", time: "30 min")
}
}

This makes it super easy to quickly for example changing the image, and directly see the results in the preview.

Note: You can use the same views also in the preview. For example, we could wrap the ImageCard in a VStack and add a second ImageCard with different values!

struct ImageCard_Previews: PreviewProvider {
static var previews: some View {
VStack {
ImageCard(image: "Dance", title: "Evening Dance", time: "50 min")
ImageCard(image: "Yoga", title: "Lunch-Time Yoga", time: "30 min")
}
}
}
Using Variables to reuse the same view and display it with different data
Showing preview with different data

2. Creating multiple Previews

Just putting different previews beside each other in a Stack works but isn’t always the best way if we want to test views with different data completely separately.

To create a second preview we can simply use the Group View and then add up to 10 previews. To add a Group you can either replace the previously created VStack with Group, or you can always command left click on a view and then select “Group” to embed the View in a Group.

struct ImageCard_Previews: PreviewProvider {
static var previews: some View {
Group {
ImageCard(image: "Dance", title: "Evening Dance", time: "50 min")
ImageCard(image: "Yoga", title: "Lunch-Time Yoga", time: "30 min")
}
}
}

On top of your preview you will now see a second label with the same name where you can switch between the two previews!

Using the Group View allows to create multiple Previews that can be switched between with the labels at the top of the preview window.
Use Group to create multiple Previews

3. Customizing Previews Name and Device Type

Having different previews is great but except for maybe showing different data there is not much difference so far. However, we can easily set what device the preview should show. For example, we want to see the first image card on an iPhone and the second on an iPad. We can do so by just changing the .previewDevice().

struct ImageCard_Previews: PreviewProvider {
static var previews: some View {
Group {
ImageCard(image: "Dance", title: "Evening Dance", time: "50 min")
.previewDevice(PreviewDevice(rawValue: "iPhone 14 Pro"))
ImageCard(image: "Yoga", title: "Lunch-Time Yoga", time: "30 min")
.previewDevice(PreviewDevice(rawValue: "iPad Pro (11-inch) (4th generation)"))
}
}
}
Using Group and setting the preview device allows to quickly test a view on multiple different devices and easily swap between them
Using Group and .previewDevice() to test the preview on two devices

If we want to test more devices we can just add another ImageCard and change to Device.

Note: You can get a list of all supported preview device names by running the following command in your terminal:

xcrun simctl list devicetypes
Running xcrun for a list of possible device types that can be used in the SwiftUI preview
Running xcrun for a list of possible device types

Quickly changing the preview like this is amazing for testing your layout on different devices. For a little bit of organization we can even name the previews differently to easily show which preview is displaying what.

struct ImageCard_Previews: PreviewProvider {
static var previews: some View {
Group {
ImageCard(image: "Dance", title: "Evening Dance", time: "50 min")
.previewDevice(PreviewDevice(rawValue: "iPhone 14 Pro"))
.previewDisplayName("ImageCard on iPhone")
ImageCard(image: "Yoga", title: "Lunch-Time Yoga", time: "30 min")
.previewDevice(PreviewDevice(rawValue: "iPad Pro (11-inch) (4th generation)"))
.previewDisplayName("ImageCard on iPad")
}
}
}
After adding .previewDisplayName() its easier to differentiate between the different previews and what they display.
Adding .previewDisplayName() to quickly differentiate between the different previews

4. Customizing the Previews Size

While it is great that we can test a view directly on multiple devices, sometimes we just want to preview the actual view and don’t get distracted how it looks in a device.

Instead of just getting the full device we can just define a size for the preview with .previewLayout(). We can pass three values to this method:

  • device
  • fixed(width: CGFloat, height: CGFloat)
  • sizeThatFits
struct ImageCard_Previews: PreviewProvider {
static var previews: some View {
ImageCard(image: "Dance", title: "Evening Dance", time: "50 min")
.previewLayout(.fixed(width: 300, height: 350))

}
}

If you want to test it without a device you could for example use .previewLayout(.sizeThatFits), which will wrap it around the content, or set a size yourself with .fixed().

Setting the preview layout and changing to Selectable preview mode to only see the actual content
Setting the preview layout and changing to Selectable preview mode

Note: Setting the frame size to a fixed size won’t show any effect in live preview mode. Change to Selectable to see the change.

Thank You! ❤️

First of all, congratulations if you made it until here and I hope you found some of the tips helpful! 👍

And if you did enjoy this story please follow me for more stories! 😊

--

--

Ix76y
Ix76y

Written by Ix76y

Hi my name is Izzy. I love to write code, currently my favorits are Python, Swift, Rust & C and I enjoy writing tutorials about all sorts of things 😊.

No responses yet