Categories
iOS Swift SwiftUI Xcode

Discovering #Preview macro in Swift

Previews are snippets of codes for creating a live preview of a view what we can see in Xcode. This enables to quickly iterate your views because we can see right away how the view looks after each of the code change. Previews are compiled alongside with the app, and therefore we can access all the other code and resources like images. If we want to use preview only resource, we can use Xcode’s development assets feature for making the resource only part of the app when rendering previews. Now when we know what previews are in general, let’s move on to creating a preview.

So far we have created a new struct which conforms to a PreviewProvider protocol if we wanted Xcode to render the view for us. Xcode 15 with Swift 5.9’s macro support introduces a #Preview macro, which replaces the old way of creating live previews. The benefit of the new macro is having to write less code to get going with live previews. Let’s compare the both approaches and have a look at an accessory view’s preview.

// Before
struct RatingsView_Previews: PreviewProvider {
static var previews: some View {
VStack {
ForEach(0…5, id: \.self) { value in
RatingsView(value: .constant(value))
}
}
.previewLayout(.sizeThatFits)
}
}
// After
#Preview(traits: .sizeThatFitsLayout) {
VStack {
ForEach(0…5, id: \.self) { value in
RatingsView(value: .constant(value))
}
}
}
view raw Preview.swift hosted with ❤ by GitHub

In the example above, we wanted to apply a trait since this view is a tiny accessory view, and therefore we would like to see it rendered as small as possible. A list of traits what we can use are listed here:

extension PreviewTrait where T == Preview.ViewTraits {
/// Preview with `.device` layout (the default).
public static var defaultLayout: PreviewTrait<Preview.ViewTraits> { get }
public static var sizeThatFitsLayout: PreviewTrait<Preview.ViewTraits> { get }
public static func fixedLayout(width: CGFloat, height: CGFloat) -> PreviewTrait<T>
public static var portrait: PreviewTrait<Preview.ViewTraits> { get }
public static var landscapeLeft: PreviewTrait<Preview.ViewTraits> { get }
public static var landscapeRight: PreviewTrait<Preview.ViewTraits> { get }
public static var portraitUpsideDown: PreviewTrait<Preview.ViewTraits> { get }
}

When working with full screen views, the preview macro can be as simple as this:

#Preview {
OnboardingView()
}

In addition to traits, we can also give a name to the preview which is displayed in the Xcode’s preview canvas. This can be useful if we create multiple previews for the same view.

A view with multiple previews with different names.

Another thing to note is that the preview canvas in Xcode also lists a pin button next to the name of the preview. Pinning previews is useful if we want to navigate to another file to make some changes and keeping the preview running. Maybe we want to change some constants which affects the layout of the view, but these constants are defined somewhere else. Then it is useful to keep the preview running and seeing how changing a constant in another view is reflected by the view using it.

There is another tip to keep in mind. We can run previews on physical devices as well. We just need to pick the physical device instead of a simulator from the device picker.

Preview canvas, which lists a physical device for preview.

Finally, let’s not forget about the great way to see all the colour scheme and dynamic type variants at the same time. There is a separate variants button for that next to the live preview and selectable preview buttons.

If this was helpful, please let me know on Mastodon@toomasvahter or Twitter @toomasvahter. Feel free to subscribe to RSS feed. Thank you for reading.