Picker が正しく表示されない

Picker でチェックボックスが表示されないバグはstack overflow (opens new window)でも報告されていて、いろいろ解決法が載っていますが、この方法では解決しません。

バグについて

  • 選択しているにも関わらずチェックマークが表示されない
  • 選択範囲がおかしい
    • Form 内の Picker は全範囲にタップ判定があるのだが、このバグが発生するとラベルにしかタップ判定がない

バグが発生しないコード

以下のコードは普通に動作する。

import SwiftUI
struct ContentView: View {
    @State var selection: FruitType = .apple
    private var timers = Array(FruitType.allCases)
    var body: some View {
        NavigationView {
            Form {
                Picker(selection: $selection, label: Text("Select")) {
                    ForEach(fruits, id:\.rawValue) {
                        Text($0.rawValue)
                    }
                }
            }
            .navigationTitle("Picker")
        }
    }
}
enum FruitType: String, CaseIterable {
    case apple
    case orange
    case banana
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

バグを含むコード

以下のコードは実行すると Picker にバグが発生する。

import SwiftUI
struct ContentView: View {
    @State var selection: FruitType = .apple
    private var timers = Array(FruitType.allCases)
    var body: some View {
        NavigationView {
            Form {
                Picker(selection: $selection, label: Text("Select")) {
                    ForEach(fruits, id:\.rawValue) {
                        Text($0.rawValue)
                    }
                }
            }
            .navigationTitle("Picker")
        }
        .buttonStyle(PlainButtonStyle())
    }
}
enum FruitType: String, CaseIterable {
    case apple
    case orange
    case banana
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

バグの原因について

要するにNavigationView.buttonStyle(PlainButtonStyle())がかかっているとForm内のPickerの表示がおかしくなってしまう。

なので、.buttonStyle(PlanButtonStyle())をネストの浅いところに書いてしまうのは良くない。特に、WindowGroupに書くと全ビューにスタイルが適応されて便利なのだが、もしも Picker を利用するつもりであれば.buttonStyle()を書く場所はしっかりと考えたほうが良い。

おまけ

iOS 向けの Style は以下の三つが使えるが、DefaultButtonStyle以外はバグが発生します。

バグ
PlainButtonStyle 発生
DefaultButtonStyle 発生しない
BorderlessButtonStyle 発生