📋
macOSのSwiftUI.Formをカスタマイズ
MacにおけるForm
macOS用のアプリをSwiftUIで開発する際、Form
は便利なツールです。
標準アプリと同様の設定画面を容易に作成できる他、現在の設定アプリと似たリスト型の画面を作成できます。この記事では後者で利用されているGroupedFormStyleのカスタマイズ方法を紹介します。
カスタマイズ方法
Formの各セクションはGroupBox(DefaultGroupBoxStyle)が利用されているため、GroupBoxStyleをカスタマイズすることでFormのカスタマイズが可能になります。
GroupBoxStyleの作成
struct CustomGroupBoxStyle: GroupBoxStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.content
}
}
// 利用例
Form {
...
}
.groupBoxStyle(CustomGroupBoxStyle())
CustomGroupBoxStyle
をForm
につけることでGroupBox
が装飾していた背景と枠が消えます。
デフォルト | CustomGroupBox |
---|---|
![]() |
![]() |
このように各Section
のコンテンツは、形の変形や色付け、回転などある程度のカスタマイズをすることができます。しかし、ヘッダーやフッターはGroupBox
で作成されていないためGroupBoxStyle
からカスタマイズはできません。
また、同じForm
内で2つ以上の異なるGroupBoxStyle
をつけることができず、必ずForm
に付く形でコードに記述する必要があります。
角丸 | レトロゲーム風 | 大体思いつくことはできる |
---|---|---|
![]() |
![]() |
![]() |
サンプルコード
import SwiftUI
struct ContentView: View {
var body: some View {
Form {
Section("Header 1") {
ForEach(1..<4) { i in
Text(String(repeating: "\(i)", count: i))
}
}
Section {
ForEach(4..<7) { i in
Text(String(repeating: "\(i)", count: i))
}
} header: {
Text("Header 2")
}
}
.formStyle(.grouped)
.groupBoxStyle(.custom)
}
}
struct CustomGroupBoxStyle: GroupBoxStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.content
// rounded
// .fontDesign(.rounded)
// .padding(4)
// .background()
// .clipShape(.rect(cornerRadius: 16))
// .overlay {
// RoundedRectangle(cornerRadius: 16)
// .strokeBorder()
// .foregroundStyle(Color(.separatorColor))
// }
// retro
// .background()
// .shadow(radius: 1, x: 1, y: 1)
// .overlay {
// Rectangle()
// .strokeBorder()
// .foregroundStyle(.secondary)
// }
// .fontWidth(.expanded)
// .background {
// Rectangle()
// .foregroundStyle(.secondary)
// .offset(x: 4, y: 4)
// }
// custom
// .rotationEffect(.degrees(180), anchor: .center)
// .overlay {
// UnevenRoundedRectangle(
// topLeadingRadius: 16,
// bottomLeadingRadius: 64,
// bottomTrailingRadius: 32,
// topTrailingRadius: 128,
// style: .continuous
// )
// .strokeBorder(lineWidth: 4)
// .foregroundStyle(
// .linearGradient(
// colors: [.red, .blue],
// startPoint: .topLeading,
// endPoint: .bottomTrailing
// )
// )
// }
}
}
extension GroupBoxStyle where Self == CustomGroupBoxStyle {
static var custom: Self { Self() }
}
#Preview {
ContentView()
.frame(width: 400, height: 400)
}
Discussion