SwiftUI ToggleStyle の作成
ToggleStyle プロトコルを使うと、標準のスイッチとは異なるトグルの見た目を実現できる。チェックボックス風、ボタン風、カスタムアニメーション付きなど、さまざまなバリエーションを作成可能だ。
ToggleStyle の基本
ToggleStyle プロトコルは makeBody(configuration:) メソッドを要求する。
struct CheckboxToggleStyle: ToggleStyle {
func makeBody(configuration: Configuration) -> some View {
HStack {
Image(systemName: configuration.isOn ? "checkmark.square.fill" : "square")
.foregroundColor(configuration.isOn ? .blue : .gray)
.font(.title2)
.onTapGesture {
configuration.isOn.toggle()
}
configuration.label
}
}
}configuration.isOn で現在の状態を取得し、変更できる。configuration.label には Toggle に渡されたラベルが入っている。
Toggle("利用規約に同意する", isOn: $agreed)
.toggleStyle(CheckboxToggleStyle())押下アクションの実装
トグルの状態を変更するには、configuration.isOn を直接変更するか、onTapGesture を使う。
struct TappableToggleStyle: ToggleStyle {
func makeBody(configuration: Configuration) -> some View {
Button {
configuration.isOn.toggle()
} label: {
HStack {
configuration.label
Spacer()
Image(systemName: configuration.isOn ? "checkmark.circle.fill" : "circle")
.foregroundColor(configuration.isOn ? .green : .gray)
}
}
.buttonStyle(.plain)
}
}Button でラップすることで、行全体がタップ可能になる。
カスタムスイッチの作成
標準のスイッチを模倣しつつ、色やサイズをカスタマイズする例。
struct CustomSwitchStyle: ToggleStyle {
var onColor: Color = .green
var offColor: Color = .gray.opacity(0.3)
var thumbColor: Color = .white
func makeBody(configuration: Configuration) -> some View {
HStack {
configuration.label
Spacer()
RoundedRectangle(cornerRadius: 16)
.fill(configuration.isOn ? onColor : offColor)
.frame(width: 50, height: 30)
.overlay(
Circle()
.fill(thumbColor)
.shadow(radius: 1)
.padding(2)
.offset(x: configuration.isOn ? 10 : -10)
)
.onTapGesture {
withAnimation(.spring(duration: 0.2)) {
configuration.isOn.toggle()
}
}
}
}
}アニメーション付きでスムーズに切り替わるカスタムスイッチが実現できる。
ボタン風トグル
struct ButtonToggleStyle: ToggleStyle {
func makeBody(configuration: Configuration) -> some View {
Button {
configuration.isOn.toggle()
} label: {
configuration.label
.padding(.horizontal, 16)
.padding(.vertical, 8)
.background(
RoundedRectangle(cornerRadius: 8)
.fill(configuration.isOn ? Color.blue : Color.gray.opacity(0.2))
)
.foregroundColor(configuration.isOn ? .white : .primary)
}
.buttonStyle(.plain)
.animation(.easeInOut(duration: 0.15), value: configuration.isOn)
}
}Toggle("フィルター ON", isOn: $filterEnabled)
.toggleStyle(ButtonToggleStyle())選択状態がボタンの色で表現される、フィルターボタンのような UI に適している。
アイコン付きトグル
struct IconToggleStyle: ToggleStyle {
var onIcon: String
var offIcon: String
var onColor: Color = .blue
var offColor: Color = .gray
func makeBody(configuration: Configuration) -> some View {
HStack {
configuration.label
Spacer()
Image(systemName: configuration.isOn ? onIcon : offIcon)
.font(.title2)
.foregroundColor(configuration.isOn ? onColor : offColor)
.onTapGesture {
withAnimation {
configuration.isOn.toggle()
}
}
}
}
}
extension ToggleStyle where Self == IconToggleStyle {
static func icon(on: String, off: String) -> IconToggleStyle {
IconToggleStyle(onIcon: on, offIcon: off)
}
}Toggle("お気に入り", isOn: $isFavorite)
.toggleStyle(.icon(on: "heart.fill", off: "heart"))セグメント風トグル
struct SegmentToggleStyle: ToggleStyle {
var onLabel: String = "ON"
var offLabel: String = "OFF"
func makeBody(configuration: Configuration) -> some View {
HStack {
configuration.label
Spacer()
HStack(spacing: 0) {
Text(offLabel)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(configuration.isOn ? Color.clear : Color.blue)
.foregroundColor(configuration.isOn ? .primary : .white)
Text(onLabel)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(configuration.isOn ? Color.blue : Color.clear)
.foregroundColor(configuration.isOn ? .white : .primary)
}
.background(Color.gray.opacity(0.2))
.cornerRadius(8)
.onTapGesture {
withAnimation {
configuration.isOn.toggle()
}
}
}
}
}セグメントコントロール風の見た目で、2 択の切り替えを表現する。
適切なスタイル選択
標準スイッチ(.switch)
設定画面など、一般的な ON/OFF 切り替え。
チェックボックス
複数項目からの選択、同意確認など。
ボタン風
フィルターやタグの選択状態を表す場合。
アイコン
お気に入り、ブックマークなど、意味が明確なアクション。
Toggle の見た目を変えることで、同じ機能でもユーザーへの印象が大きく変わる。アプリのデザインシステムに合わせて適切なスタイルを選択・作成することが重要だ。











