🐈

Xcode Previews上で複数の端末での表示を確認する

2020/09/22に公開

Xcode Previewsで表示する端末を指定する

基本的にはXcodeで現在選択しているSimulatorのDeviceが使用されます。
例えばiPhone 11 Proを現在選択している場合には、iPhone 11 Pro上でViewが描画され、previewを見ることができます。

struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
            .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
       ContentView() // display ContentView with selected simulator
    }
}

SwiftUIのドキュメントの中で、以下のような記述を見ることができます。

    /// If you set the preview device to `nil`, as it is by default, Xcode
    /// automatically chooses an appropriate device based on your target.

もしそれ以外の特定の端末での表示を確認したい場合はpreviewDeviceを使います。

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
       ContentView()
          .previewDevice("iPhone 8") // Specify device as iPhone 8
    }
}

これで、例えばSimulatorの選択がiPhone XS Maxだったとしても、PreviewsではiPhone8の端末が使用され、指定したViewがPreviewされます。

更に、.previewDisplayNameに文字列を渡すことで、Previewされている端末の上部に表示される名前を変更することができます。

ContentView()
    .previewDevice("iPhone 8")
    .previewDisplayName("iPhone 8")

注意点

previewDeviceで指定する端末の名前は、Simulatorを選択するときに表示されている名前と同じものを使う必要があります。
(2nd generation)(11 inch)といった文字列も正しくそのまま指定する必要があります。
なので、例えば11ichのiPad Proの第2世代を使ってPreviewしたい場合はiPad Proではだめで、
iPad Pro (11-inch) (2nd generation) と指定する必要があります。

また、previewDeviceのメソッドに渡す値はPreviewDeviceという型である必要があります。
ただ、この型はExpressibleByStringLiteralに適合しているため、文字列リテラルであれば直接指定することが出来ます。
もし文字列の変数を与えたい場合は以下のようにPreviewDevice型を生成する必要があります。

let deviceName = "iPhone 8"
let previewDevice = PreviewDevice(rawValue: deviceName)

複数端末表示する

ForEachを使うことで、簡単に複数の端末をPreviewsに並べて表示することができます。

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        let devices = ["iPhone 8", "iPhone 11 Pro Max"]
        ForEach(devices, id: \.self) { device in
            ContentView()
                .previewDevice(.init(rawValue: device))
                .previewDisplayName(device)
        }
    }
}

より扱いやすく

他のViewでも同様にPreviewしたい場合に同じようなコードを書くのは面倒なので以下のようなコードを用意しPreviewする処理を共通化します

enum XcodePreviewsDevice: String, CaseIterable {
    case iPhone8 = "iPhone 8"
    case iPhone11ProMax = "iPhone 11 Pro Max"
    case iPadAir = "iPad Air (4th generation)"
    // Add more case you want to display

    static func previews<C: View>(
        _ devices: [XcodePreviewsDevice] = XcodePreviewsDevice.allCases,
        content: @escaping () -> C) -> some View {
        ForEach(devices, id: \.self) {
            content()
                .previewDevice(.init(rawValue: $0.rawValue))
                .previewDisplayName($0.rawValue)
        }
    }
}

上記のコードではiPhone 8, iPhone 11 Pro Max, iPad AirでのPreviewが確認できるようになります。
必要に応じて表示したい端末を追加編集してください。

さて、上記コードを書いたら、次のようにコードを書き換えてみましょう。

// Show all devices in Xcode Previews
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        XcodePreviewsDevice.previews { ContentView() }
    }
}

// Show specific devices in Xcode Previews
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        XcodePreviewsDevice.previews([.iPhone8, .iPadAir]) { ContentView() }
    }
}
p

最終的には1行で自分の確認したい複数の端末でXcode Previewsを表示することができるようになりました 🍀
よかったら活用してみてください🙌

最後に

もし記事が役に立った!参考になった!という場合はLikeしてもらえると嬉しいです 🙌
今後の技術ネタの投稿のモチベーションになります。
サポートもお待ちしています 🐈

Discussion