😺

【SwiftUI】カードみたいにコンテンツを表示をするときはGroupBoxを使うと便利だよ

2024/10/29に公開

GroupBoxとは

今回は、SwiftUIの便利なViewのひとつ「GroupBox」を紹介します。

GroupBoxは意味のあるひとまとまりのコンテンツを視覚的にわかりやすく表示してくれるViewです。

言葉で説明するとわかりにくいので、Apple公式ドキュメントのサンプルをご覧ください。こちらのサンプルのように、カードのような見た目で表示してくれるコンポーネントです。
GroupBox | Apple Developer Documentation

GroupBoxを使ってみよう

こちらのサンプルはわたしがリリースした集中アプリのFocus Rainbowです。
Screen Time APIを使って、今集中したいアプリだけを実行することができます。
便利なタイマー機能や、楽しいキャラクターが集中をサポートしてくれるので、ぜひお試しください!

https://apps.apple.com/jp/app/focus-rainbow/id6569223924

Focus Rainbowではアプリの使い方のコツを紹介する画面を用意していて、その中に「自分のスマホを人に貸すときに大事なアプリをガードする」説明があります。
設定方法の手順を記載している箇所は、ひとまとまりの情報なのでスクリーンショットのように枠で囲っています。

この部分のコードは、下記のとおりです。

    VStack(spacing: 10) {
        VStack(alignment: .leading, spacing: 20) {
            Text("1. アクティビティを追加します。")
            Text("2. アプリを選択ボタンをタップして、触っていいアプリだけを選んで登録します。")
            Text("3. 追加したアクティビティをタップして、集中するボタンをタップします。")
            Text("4. スマホを貸す時間を設定して、開始ボタンをタップします。")
            Text("5. ミッション完了!安心してスマホを渡せます。")
            Text("注意!")
                .font(.headline)
            Text("「大事なアプリをいつも使えるようにする」で紹介した方法で登録したアプリはガードされません。設定を見直すのをお忘れなく。")
        }
    }
    .padding()
    .overlay(RoundedRectangle(cornerRadius: 15).stroke(Color.accentColor, style: StrokeStyle(lineWidth: 1)))
    .clipShape(.rect(cornerRadius: 15))

では、このコードをGroupBoxに書き換えてみましょう。

    GroupBox {
        VStack(alignment: .leading, spacing: 10) {
            Text("1. アクティビティを追加します。")
            Text("2. アプリを選択ボタンをタップして、触っていいアプリだけを選んで登録します。")
            Text("3. 追加したアクティビティをタップして、集中するボタンをタップします。")
            Text("4. スマホを貸す時間を設定して、開始ボタンをタップします。")
            Text("5. ミッション完了!安心してスマホを渡せます。")
            Text("注意!")
                .font(.headline)
            Text("「大事なアプリをいつも使えるようにする」で紹介した方法で登録したアプリはガードされません。設定を見直すのをお忘れなく。")
        }
        .padding(.top)
    } label: {
        Label("設定方法", systemImage: "info.circle")
    }

GroupBoxに定義されている init(content:label:) というInitializerを使用しています。
contentにメインの情報を、labelにタイトル的な情報を設定します。

では、GroupBoxで書いたものを見てみましょう。
いい感じです。標準コンポーネントなので、ダークモード対応もバッチリですね。

ライトモード ダークモード

GroupBoxStyleでカスタマイズ

ただ、元のサンプルとはだいぶ見た目が違うので、カスタマイズしてみましょう。
カスタマイズするときは、 GroupBoxStyle を使用します。

labelとcontentは左寄せにしたいので、VStackで囲んでalignmentを.leadingにしています。
また、アクセントカラーの枠線をつけて、角丸にしています。

struct RoundedCornerGroupBoxStyle: GroupBoxStyle {
    func makeBody(configuration: Configuration) -> some View {
        VStack(alignment: .leading) {
            configuration.label
            configuration.content
        }
        .padding()
        .overlay(RoundedRectangle(cornerRadius: 15).stroke(Color.accentColor, style: StrokeStyle(lineWidth: 1)))
        .clipShape(.rect(cornerRadius: 15))
    }
}

GroupBoxにGroupBoxStyleを適用するときは、 groupBoxStyle(_:) を使用します。

    GroupBox {
        VStack(alignment: .leading, spacing: 10) {
            Text("1. アクティビティを追加します。")
// (中略)
        }
        .padding(.top)
    } label: {
        Label("設定方法", systemImage: "info.circle")
    }
    .groupBoxStyle(RoundedCornerGroupBoxStyle())

では、さっそく結果を見比べてみましょう。
いい感じですね。元のサンプルと同じようになりました。

元のサンプル GroupBoxStyleで書いたもの

まとめ

個人で開発しているアプリはできるだけAppleが提供しているコンポーネントを使って標準的なUIに近づけるように気をつけています。

標準的なUIに近いと、ユーザーは馴染みがあるのでとっつきやすくなります。また、標準のコンポーネントを使用すると、OSをアップデートしても壊れにくいですし、iPad OSやtvOSなど複数デバイス対応もやりやすくなります。

コンテンツのグループを作るときは、GroupBoxを試してみてください。

Discussion