
SwiftUIでサイズクラスに応じてレイアウトを変える
Size Classとは、iOS開発における様々なデバイスや向きに対応したAdaptiveレイアウトを実現する上での重要な概念であり、今回はSwiftUIでSize Classを使ってレイアウトを変える方法を簡単に紹介する。
Size Classの細かい定義はHuman Interface Guidelinesに記載されているが、ざっくり以下の組み合わせとなっている。 ※Size ClassはiPadでのSplit Viewにも適用される

SwiftUIでSize Classを使う
Size ClassはEnrivonment property wrapperを使って以下のように定義できる(こちらを参照)。
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
@Environment(\.verticalSizeClass) private var verticalSizeClass
horizontalSizeClass, verticalSizeClassは以下のようなEnum値を取るので、body内で条件分岐してレイアウトを切り替えることができる。
public enum UserInterfaceSizeClass {
case compact
case regular
}
以下のコードでは、予め縦向きや横向きのレイアウトを定義し、条件分岐でそれぞれのレイアウトを切り替えることでAdaptiveレイアウトを実現している。ただし、iPadでは縦横ともにRegularとなってしまうので、iPadの縦横画面でレイアウトを変更したい場合は、画面回転の検知など別のアプローチも必要となる。 ※if文による記述は長いので、こちらの記事のようにSize Classの組み合わせでEnumを定義してもよい。
struct ContentView: View {
@Environment(\\.horizontalSizeClass) private var horizontalSizeClass
@Environment(\\.verticalSizeClass) private var verticalSizeClass
var body: some View {
if (horizontalSizeClass == .regular && verticalSizeClass == .compact) ||
(horizontalSizeClass == .compact && verticalSizeClass == .compact) {
// Landscape (iPhone)
landscapeLayout
} else if horizontalSizeClass == .compact && verticalSizeClass == .regular {
// Portrait (iPhone)
portraitLayout
} else {
// iPad
landscapeLayout
}
}
}
private extension ContentView {
/// 縦向きのレイアウト
var portraitLayout: some View {
VStack {
Color(UIColor.red).frame(width: 200, height: 200)
Color(UIColor.green).frame(width: 200, height: 200)
Color(UIColor.blue).frame(width: 200, height: 200)
}
}
/// 横向きのレイアウト
var landscapeLayout: some View {
HStack {
Color(UIColor.red).frame(width: 200, height: 200)
Color(UIColor.green).frame(width: 200, height: 200)
Color(UIColor.blue).frame(width: 200, height: 200)
}
}
}
