【SwiftUI】ちょっとリッチに切り替えボタンを実装!セグメントコントロール

Swift

ちょっとリッチに、画面の色とか表示内容を変えたかったのでセグメントコントロールをアプリに実装してみました。

SwiftUIではセグメントコントロールが用意されていないので、Pickerを用いてセグメントコントーロールを実装しました。

今回実装ゴールは以下動画のものです。

ボタンが中央に3つ横並びに並んでいて、それぞれのボタンを押すことで動的に下の文字を変えています。

Picker

今回セグメントコントロールの為に使用するSwiftUI部品はPickerです。

元々は複数の選択肢を表示して、ユーザーに一つを選択させるような部品ですがモディファイアを指定することで、セグメントコントロールのような部品に変更することが可能です。

Picker("タイトル(任意)", selection: $selectedFlavor) {
        // 選択肢のView
}
.pickerStyle(.pickerのスタイル指定)

タイトル

Pickerを表示する際に表示されるタイトルになります。

.pickerStyleの指定するオプションによっては表示されない場合があります。

selection

変更された際に、更新される変数を指定します。

Pickerの選択肢が変更された際にこの変数が更新されます。

.pickerStyle

Pickerの表示スタイルを変更するためのモディファイアです。

色々なスタイルがあるので都度自分の使いたいものに変更していきましょう。

.automatic

.pickerStyleモディファイアを指定しなかった際に設定されるデフォルトのモディファイアです。

クリックすると選択肢が縦に並んで表示されます。

選択すると左側にチェックマークが付きます。

実装コード

import SwiftUI

struct SettingView: View {
    // フルーツの選択使用の列挙型を定義
    private enum Fruit: String, CaseIterable, Identifiable {
        case apple = "Apple"
        case banana = "Banana"
        case orange = "Orange"

        var id: String { rawValue }
    }
    // 初期値をAppleに指定する
    @State private var selection = Fruit.apple
    var body: some View {
        VStack {
            Picker("フルーツ", selection: $selection) {
                ForEach(Fruit.allCases) { fruit in
                    Text(fruit.rawValue).tag(fruit)
                }
            }
            .pickerStyle(.automatic) // 自動的にスタイルを選択
            .padding()
            Text("選択されたモード: \(selection.id)")
        }
    }
}
.inline

最初から選択肢が全て表示されます。選択肢をクリックすると右にチェックマークが付きます。

コードを書く際に、FormかListでPickerを囲む必要があります。

実装コード

import SwiftUI

struct SettingView: View {
    // フルーツの選択使用の列挙型を定義
    private enum Fruit: String, CaseIterable, Identifiable {
        case apple = "Apple"
        case banana = "Banana"
        case orange = "Orange"

        var id: String { rawValue }
    }
    // 初期値をAppleに指定する
    @State private var selection = Fruit.apple
    var body: some View {
        VStack {
        // FormかListで囲む必要あり
            Form{
                Picker("フルーツ", selection: $selection) {
                    ForEach(Fruit.allCases) { fruit in
                        Text(fruit.rawValue).tag(fruit)
                    }
                }
                .pickerStyle(.inline)
                .padding()
            }
            Text("選択されたモード: \(selection.id)")
        }
    }
}
.menu

.automaticと表示は同じです。

実装コード

import SwiftUI

struct SettingView: View {
    // フルーツの選択使用の列挙型を定義
    private enum Fruit: String, CaseIterable, Identifiable {
        case apple = "Apple"
        case banana = "Banana"
        case orange = "Orange"

        var id: String { rawValue }
    }
    // 初期値をAppleに指定する
    @State private var selection = Fruit.apple
    var body: some View {
        VStack {
            Picker("フルーツ", selection: $selection) {
                ForEach(Fruit.allCases) { fruit in
                    Text(fruit.rawValue).tag(fruit)
                }
            }
            .pickerStyle(.menu) // 自動的にスタイルを選択
            .padding()
            Text("選択されたモード: \(selection.id)")
        }
    }
}
.navigationLink

選択肢を別画面でリスト表示する形式です。

PickerがnavigationLinkの表示になっていてクリックすると別画面に移動します。

別画面では選択肢をリスト表示しています。選択肢画面での選択が、元画面にも反映されます。

実装コード

import SwiftUI

struct SettingView: View {
    // フルーツの選択使用の列挙型を定義
    private enum Fruit: String, CaseIterable, Identifiable {
        case apple = "Apple"
        case banana = "Banana"
        case orange = "Orange"

        var id: String { rawValue }
    }
    // 初期値をAppleに指定する
    @State private var selection = Fruit.apple
    var body: some View {
        VStack {
            Form{
                Picker("フルーツ", selection: $selection) {
                    ForEach(Fruit.allCases) { fruit in
                        Text(fruit.rawValue).tag(fruit)
                    }
                }
                .pickerStyle(.navigationLink)
                .padding()
                Text("選択されたモード: \(selection.id)")
            }
        }
    }
}
.wheel

選択肢が一部しか表示されないスクロール可能な表示形式です。

他選択肢を見る際には、スクロールすることで表示させます。アルファベットや日付など選択肢が予測可能なものに使用することが推奨されています。

import SwiftUI

struct SettingView: View {
    // フルーツの選択使用の列挙型を定義
    private enum Fruit: String, CaseIterable, Identifiable {
        case apple = "Apple"
        case banana = "Banana"
        case orange = "Orange"

        var id: String { rawValue }
    }
    // 初期値をAppleに指定する
    @State private var selection = Fruit.apple
    var body: some View {
        VStack {
            Form{
                Picker("フルーツ", selection: $selection) {
                    ForEach(Fruit.allCases) { fruit in
                        Text(fruit.rawValue).tag(fruit)
                    }
                }
                .pickerStyle(.wheel)
                .padding()
                Text("選択されたモード: \(selection.id)")
            }
        }
    }
}
.segment

選択肢が横並びに並ぶ表示方法です。

UIKitの際のセグメントコントロールの代わりに使用可能です。

実装コード

import SwiftUI

struct SettingView: View {
    // フルーツの選択使用の列挙型を定義
    private enum Fruit: String, CaseIterable, Identifiable {
        case apple = "Apple"
        case banana = "Banana"
        case orange = "Orange"

        var id: String { rawValue }
    }
    // 初期値をAppleに指定する
    @State private var selection = Fruit.apple
    var body: some View {
        VStack {
            Picker("フルーツ", selection: $selection) {
                ForEach(Fruit.allCases) { fruit in
                    Text(fruit.rawValue).tag(fruit)
                }
            }
            .pickerStyle(.segmented)
            .padding()
            Text("選択されたモード: \(selection.id)")
        }
    }
}

セグメントコントロールの実装

Pickerの.segmentを用いて実装していきます。

import SwiftUI

struct SettingView: View {
    // フルーツの選択使用の列挙型を定義
    private enum Fruit: String, CaseIterable, Identifiable {
        case apple = "Apple"
        case banana = "Banana"
        case orange = "Orange"

        var id: String { rawValue }
    }
    // 初期値をAppleに指定する
    @State private var selection = Fruit.apple
    var body: some View {
        VStack {
            Picker("フルーツ", selection: $selection) {
                ForEach(Fruit.allCases) { fruit in
                    Text(fruit.rawValue).tag(fruit)
                }
            }
            .pickerStyle(.segmented) 
            .padding()
            Text("選択されたモード: \(selection.id)")
        }
    }
}

Fruit型のEnumを宣言

@Stateのselection変数を宣言。Pickerでの切り替えが行われた際に、Viewを更新するようにします。

Pickerにselection変数を渡して、変更された際に格納する変数にします。

Pickerの選択肢としてForEachを用いて、Enum分だけTextで選択肢を作成します。

Textでselectionを表示して変更された際に表示を切り替えるようにしています。

終わり

今回自分のアプリにセグメントコントロールを実装したく色々と調べた結果を載せました。

UIKitとSwiftUIの間でピッタリの部品がないことが多いですが、SwiftUIの既存部品を使ってうまく表示することができました。

他にも互換性がない部品があると思います。見つけ次第記事にしていこうと思います〜!

コメント

タイトルとURLをコピーしました