Articles, podcasts and news about Swift development, by John Sundell.

Previewing SwiftUI views in landscape

Published on 25 Sep 2021
Discover page available: SwiftUI

Starting in Xcode 13, SwiftUI views can now be previewed in landscape orientation using the new previewInterfaceOrientation modifier. For example, here we’re previewing a MenuView in both portrait and landscape by creating two instances of our view within its PreviewProvider:

struct MenuView_Previews: PreviewProvider {
    static var previews: some View {
        MenuView()
        MenuView().previewInterfaceOrientation(.landscapeRight)
    }
}

Note how we only need to apply the above modifier when we want to preview a given view using an orientation other than portrait, since that orientation is used by default.

However, while the above code works perfectly fine when working on a project that has iOS 15 as its minimum deployment target, we’ll end up getting a compiler error if our app also supports earlier system versions, since (even though this is preview-specific code) we’re using an API that was introduced in iOS 15.

To solve that problem, we could either use an inline availability check:

struct MenuView_Previews: PreviewProvider {
    static var previews: some View {
        MenuView()

        if #available(iOS 15, *) {
            MenuView().previewInterfaceOrientation(.landscapeRight)
        }
    }
}

Or, we could make our entire preview provider require iOS 15:

@available(iOS 15.0, *)
struct MenuView_Previews: PreviewProvider {
    static var previews: some View {
        MenuView()
        MenuView().previewInterfaceOrientation(.landscapeRight)
    }
}

Both of the above solutions work, but it would arguably be quite inconvenient to have to insert those availability statements every single time that we want to preview one of our views in landscape.

One way to address that would be to wrap the new previewInterfaceOrientation modifier in a custom method that performs the required availability check, and then falls back to simply rendering our view as-is if previewing on an older OS version (which, at the time of writing, doesn’t even seem to be possible when using Xcode 13):

extension View {
    @ViewBuilder
    func previewInLandscape() -> some View {
        if #available(iOS 15, *) {
            previewInterfaceOrientation(.landscapeRight)
        } else {
            self
        }
    }
}

To learn more about annotating functions with the @ViewBuilder attribute, and why doing so is required in the above kind of situation, check out this short article.

With the above in place, we can now simply use our new, custom modifier method whenever we want to preview one of our views in landscape, without having to add any availability checks at each call site:

struct MenuView_Previews: PreviewProvider {
    static var previews: some View {
        MenuView()
        MenuView().previewInLandscape()
    }
}

Being able to preview SwiftUI views in landscape is a fantastic addition to Xcode’s preview system, and using the above extension we’ll be able to use this new feature without having to make our preview code any more complicated.

Hope you’ll find this tip useful, and thanks for reading!