Yappli Tech Blog

株式会社ヤプリの開発メンバーによるブログです。最新の技術情報からチーム・働き方に関するテーマまで、日々の熱い想いを持って発信していきます。

画面回転でLazyVGridのカラム数を変更する

こんにちは、iOSエンジニアの西村です。

今回は、SwiftUIのLazyVGridを使って画面回転に応じてカラム数を変更する処理を実装したいと思います。

縦画面(2列での表示) 横画面(4列での表示)

LazyVGridで絵文字を表示する

まずは、LazyVGridを使用してUnicodeと絵文字をそれぞれ2列で表示してみました。

コードは、LazyVGridのドキュメントにサンプルとして掲載されているものをそのまま使用しています。

developer.apple.com

このコード内でカラム数を定義しているのは、2行目のcolumns変数です。この変数でGridItemの数を増やすと、それに応じてカラム数も増えていきます。

あとは画面回転を検知してGridItemの数を調整すれば、目的を果たせそうですね!

struct VerticalSmileys: View {
    let columns = [GridItem(.flexible()), GridItem(.flexible())]

    var body: some View {
         ScrollView {
             LazyVGrid(columns: columns) {
                 ForEach(0x1f600...0x1f679, id: \.self) { value in
                     Text(String(format: "%x", value))
                     Text(emoji(value))
                         .font(.largeTitle)
                 }
             }
         }
    }

    private func emoji(_ value: Int) -> String {
        guard let scalar = UnicodeScalar(value) else { return "?" }
        return String(Character(scalar))
    }
}

画面回転を検知してカラム数を変更する

次は画面回転を検知していきます。

画面回転を検知するには、horizontalSizeClassverticalSizeClassを使用します。これら値は、それぞれの方向における利用可能なスペースの量を示します。
これで、縦方向および横方向のビューがcompactサイズかregularサイズかを判別することができます。

@Environment(\.horizontalSizeClass) private var horizontalSizeClass
@Environment(\.verticalSizeClass) private var verticalSizeClass

developer.apple.com


具体的には下記のように使用します。

横方向(horizontalSizeClass)がcompactかつ、縦方向(verticalSizeClass)がregularの場合は端末が縦向きだと判断できるので、縦横に応じてViewの切り替えを行っています。
※ iPhoneでは縦向きであるかを正しく検知できますが、iPadでは検知できない場合があることに注意が必要です。

詳細は Human Interface Guidelines のレイアウトをご覧ください。
レイアウト | Apple Developer Documentation

struct VerticalSmileys: View {
    @Environment(\.horizontalSizeClass) private var horizontalSizeClass
    @Environment(\.verticalSizeClass) private var verticalSizeClass

    var body: some View {
        let isPortrait = (horizontalSizeClass == .compact && verticalSizeClass == .regular)
        if isPortrait {
            Text("縦画面")
        } else {
            Text("横画面")
        }
    }
}


端末の向きが検知できるようになったので、あとはLazyVGridのカラム数を端末の向きに合わせて変更していきます。
カラム数は、配列で管理されたGridItemの数に依存するので、表示したいカラム数分GridItemを配列で返す関数を作成していきます。

下記の関数では、
3行目で、「縦方向: 2カラム」「横方向: 4カラム」になるようにカラム数を調整しています。
4行目で、指定されたカラムの数だけGridItemを配列として生成する処理を実施しています。

private func generateGridItems() -> [GridItem] {
    let isPortrait = (horizontalSizeClass == .compact && verticalSizeClass == .regular)
    let columnCount: Int = isPortrait ? 2 : 4
    return Array(repeating: GridItem(.flexible()), count: columnCount)
}

あとはLazyVGridのcolumns引数に、このコードで生成したGridItemの配列を渡すことで画面の向きに応じてカラム数を変更できるようになります。


全体のコードはこのようになりました。

struct VerticalSmileys: View {
    @Environment(\.horizontalSizeClass) private var horizontalSizeClass
    @Environment(\.verticalSizeClass) private var verticalSizeClass

    var body: some View {
        let columns = generateGridItems()
        ScrollView {
            LazyVGrid(columns: columns) {
                ForEach(0x1f600...0x1f679, id: \.self) { value in
                    Text(String(format: "%x", value))
                    Text(emoji(value))
                        .font(.largeTitle)
                }
            }
        }
    }

    private func emoji(_ value: Int) -> String {
        guard let scalar = UnicodeScalar(value) else { return "?" }
        return String(Character(scalar))
    }

    /// 端末の方向によってカラム数を決める
    private func generateGridItems() -> [GridItem] {
        let isPortrait = (horizontalSizeClass == .compact && verticalSizeClass == .regular)
        let columnCount: Int = isPortrait ? 2 : 4
        return Array(repeating: GridItem(.flexible()), count: columnCount)
    }
}

実行結果

縦画面(2列での表示) 横画面(4列での表示)

最後に

今回は、SwiftUIを使って画面の向きに応じてLazyVGridのカラム数を変更する方法を紹介しました。

画面の向きに合わせて表示内容を調整できるため、よりユーザビリティが高いアプリが作成できそうです。また、UIKitに比べてコードがシンプルで読みやすくなる点も魅力です。さらにSwiftUIの特長を活かし、より効果的なUI/UXを提供できるアプリ開発を進めていきたいです。