LaTeX957300 views
いろは2986023 views
中学英語808712 views
高校化学2913383 views
りんご192546 views
高校物理158224 views
ヒストリア284143 views
Computer365120 views
高校倫理1433119 views
小学社会308636 views
Help
Tools

English

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 の見た目を変えることで、同じ機能でもユーザーへの印象が大きく変わる。アプリのデザインシステムに合わせて適切なスタイルを選択・作成することが重要だ。