10
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【SwiftUI】初期値 nil の Optional な Enum の Picker を実装する

Posted at

やりたいこと

フォームなどで Enum の値を Picker で選択させたい。
このとき、未選択の状態を nil で表現し、nil の場合は「選択してください」という項目にしたい。

実装

上の画像の実装コードを載せる。

enum Area: String, CaseIterable {
    case africa = "アフリカ"
    case asia = "アジア"
    case europa = "ヨーロッパ"
    case america = "アメリカ"
    case australia = "オーストラリア"
}
struct FormView: View {
    @State private var area: Area? = nil
    
    var body: some View {
        VStack {
            Text(area?.rawValue ?? "nilです")
            Picker("エリア", selection: $area) {
                Text("選択してください").tag(Area?(nil))
                ForEach(Area.allCases, id: \.self) { area in
                    Text(area.rawValue).tag(Area?.some(area))
                }
            }
        }
    }
}

解説

enum

String に準拠させ Picker に表示する文字を指定しておく。
さらに CaseIterable で enum を配列化できるようにする。

enum Area: String, CaseIterable {
    case africa = "アフリカ"
    case asia = "アジア"
    case europa = "ヨーロッパ"
    case america = "アメリカ"
    case australia = "オーストラリア"
}

Picker

重要なのは tag の振る舞い。
Picker の selection に適用された値に tag の値が連動するはずだが、以下だと動かない。
(そもそもこれだと nil の時の振る舞いが書かれていないが...)

struct FormView: View {
    @State private var area: Area? = nil
    
    var body: some View {
        VStack {
            Text(area?.rawValue ?? "nilです")
            Picker("エリア", selection: $area) {
                ForEach(Area.allCases, id: \.self) { area in
                    Text(area.rawValue).tag(area)
                }
            }
        }
    }
}

これは tag に与えられた area の型は Area型だが、selection に適応されているのは Area?型 であるという違いが原因。
というわけで、Area?.some(area) でラップしてあげよう。

Picker("エリア", selection: $area) {
    ForEach(Area.allCases, id: \.self) { area in
        Text(area.rawValue).tag(Area?.some(area))
    }
}

あとは nil の際の振る舞いを追加する。
こちらもタグを使い、Area? の nil であることを表現してあげよう。

Picker("エリア", selection: $area) {
    Text("選択してください").tag(Area?(nil))
    ForEach(Area.allCases, id: \.self) { area in
        Text(area.rawValue).tag(Area?.some(area))
    }
}
10
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?