SwiftUIでもSegmented Control的なものを使いたい

2022.02.26

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

SwiftUIでSegmented Control的なものを使いたいと思い、調べた記録をまとめています。

環境

  • Xcode 13.2.1

作ったもの

Pickerを使う

SwiftUIでSegemented Control的なものを表現したい時にはPickerを使います。もちろん自作するという手もありますが、今回はPickerを使用して表現する方法にしました。

Pickerとは

セットされた相互に排他的な値の選択をコントロールできるものになります。

struct Picker<Label, SelectionValue, Content> where Label : View, SelectionValue : Hashable, Content : View
  • Label
    • Pickerのラベル。このラベルは、FormList内でPickerを使用すると表示されます。
  • SelectionValue
    • 何が選択されているかの値
  • Content
    • Pickerの中身

ただ、このPickerをそのまま使用するだけではSegemented Control的な表現はできません。

pickerStyle(.segmented)

Segemented Control的な表現をするためには、PickerStyle.segementedに指定してあげる必要があります。

PickerStyleには、下記のようにたくさん種類がありますので是非試してみてください。

サンプルコード

.segmentedのスタイルを使用したサンプルコードを準備しました。

import SwiftUI

struct ContentView: View {

    enum Friends: String, CaseIterable, Identifiable {
        case ossa = "オッサ"
        case ossan = "オッサン"

        var id: String { rawValue }
    }

    @State private var selectedFriend = Friends.ossa

    var body: some View {
        Picker("友達", selection: $selectedFriend) {
            ForEach(Friends.allCases) {
                friend in
                Text(friend.rawValue).tag(friend)
            }
        }
        .pickerStyle(.segmented)
        .padding()
    }
}

プレビュー

上記のコードのプレビューはこのようになっています。

色とフォントを変更する

colorMultiplyを使用する

.colorMultiply(_:)を使用することでPickerで選択中の色を設定出来ます。

var body: some View {
    Picker("友達", selection: $selectedFriend) {
        ForEach(Friends.allCases) {
            friend in
            Text(friend.rawValue).tag(friend)
        }
     }
    .colorMultiply(.green)
    .pickerStyle(.segmented)
    .padding()
}

しかし、これだと限定的なカスタムしか出来ません。今後対応されて色々なカスタムが可能になると嬉しいですね。

UISegmentedControl.appearance()を設定する

やはりUIKitに頼るしかないのか、、ということで、

Segmented Control風Pickerの色やフォントを変更する為に、UISegmentedControl.appearance()を設定します。initメソッドを追加し、メソッド内でappearanceの設定をしてあげます。

// 追加
init() {
    let appearance = UISegmentedControl.appearance()
    let font = UIFont.boldSystemFont(ofSize: 17)
    let foregroundColor = UIColor.systemGreen

    // 選択時の背景色
    appearance.selectedSegmentTintColor = foregroundColor

    // 通常時のフォントとフォント色
    appearance.setTitleTextAttributes([
        .font: font,
        .foregroundColor: foregroundColor
    ], for: .normal)

    // 選択時のフォントとフォント色
    appearance.setTitleTextAttributes([
        .font: font,
        .foregroundColor: UIColor.white
    ], for: .selected)
}

var body: some View {
    // 省略
}

これでSegmented Control風Pickerのカスタムが出来ました。

おわりに

SwiftUIだけでPickerのカスタムが出来ず、UIKitの力を借りました。ですが、もしSwiftUIだけで完結する方法をご存知の方いましたら優しく教えていただけると幸いです。

まぁ、自分でViewをカスタムして作ればいいんでしょうけどね。

参考