I have an Optional config isAttending
which starts out as nil
. When the "+" button is pressed it should set that value to a provided a default value and the Picker should show that as the selected value.
However on "+" button press, the Picker is not highlighting the selected value. Current behavior:
Desired behavior:
Note: If some other UI component changes then the Picker gets updated to the correct visual state in that render cycle
import SwiftUI
struct QuestionView<Option, Content: View>: View {
@Binding var option: Option?
let defaultOption: Option?
@ViewBuilder let content: () -> Content
var body: some View {
VStack {
if let _ = option {
content()
} else {
Button {
option = defaultOption
} label: {
Label("Add Filter Option", systemImage: "plus")
.labelStyle(.iconOnly)
}
}
}
}
}
struct Config {
var isAttending: Bool?
}
#Preview {
@Previewable @State var config: Config = Config()
QuestionView(option: $config.isAttending, defaultOption: false) {
Picker("RSVP", selection: $config.isAttending) {
Text("Attending").tag(true)
Text("Not Attending").tag(false)
}
.pickerStyle(.segmented)
}
}
This is probably due to some quirks of the underlying UIKit UISegmentedControl
that is backing the SwiftUI Picker
. The .wheel
picker style behaves correctly.
Extracting the Picker
into its own view also works correctly.
struct AttendPicker: View {
@Binding var isAttending: Bool?
var body: some View {
Picker("RSVP", selection: $isAttending) {
Text("Attending").tag(true)
Text("Not Attending").tag(false)
}
.pickerStyle(.segmented)
}
}
QuestionView(option: $config.isAttending, defaultOption: false) {
AttendPicker(isAttending: $config.isAttending)
}
Side note: though it is unrelated to this specific problem, I'd suggest calling the content
closure of QuestionView
in init
. This makes SwiftUI eagerly pick up all the dependencies the content
has.
@Binding var option: Option?
let defaultOption: Option?
let content: Content // <----
init(option: Binding<Option?>, defaultOption: Option?, @ViewBuilder content: () -> Content) {
self._option = option
self.defaultOption = defaultOption
self.content = content() // <----
}
// ...
if let _ = option {
content // <----
} else {
...
}