Reputation: 1033
I am making a view in SwiftUI with a picker-popover. When picking a value and dismissing the view everything works fine.
But I need to be able to dismiss the picker WITHOUT setting the newly selected value, and have it go back to the initial value it had when being opened.
You can see the code here:
import SwiftUI
struct ContentView: View {
@State var showPicker = false
@State var selectedPickerOption = 0
let pickerOptions = ["Hello", "World", "Yes"]
var body: some View {
ZStack {
VStack {
Text("Selected Option: \(pickerOptions[selectedPickerOption])")
Button(
action: {
showPicker = true
},
label: {
Text("Open Picker")
.padding()
}
)
}
if showPicker {
PickerPopover(
pickerOptions: pickerOptions,
width: 300,
height: 300,
showPicker: $showPicker,
selectedPickerOption: $selectedPickerOption,
initialPickerOption: selectedPickerOption
)
.background(Color.red)
}
}
}
}
struct PickerPopover: View {
var pickerOptions: [String]
var width: CGFloat
var height: CGFloat
@Binding var showPicker: Bool
@Binding var selectedPickerOption: Int
var initialPickerOption: Int // This one doesn't work yet
func selectOption() {
withAnimation {
showPicker.toggle()
}
}
func cancel() {
// ######### THIS LINE HERE ISN'T WORKING ##############
selectedPickerOption = initialPickerOption
withAnimation {
showPicker.toggle()
}
}
var body: some View {
VStack {
Picker(
selection: $selectedPickerOption,
label: Text("")
) {
ForEach(0 ..< pickerOptions.count) {
Text(self.pickerOptions[$0])
}
}
.pickerStyle(WheelPickerStyle())
Button(action: cancel) {
Text("Cancel")
}
Button(action: selectOption) {
Text("Select")
}
}
.transition(.move(edge: .bottom))
}
}
I believe the first line in the cancel()
function should do the trick - if selectedPickerOption
is set to 0 (or 1, etc) that will reset the picker to that index specifically.
I have been unable to set it dynamically though. I have tried passing in an additional value (intialPickerOption
), but resetting selectedPickerOption = initialPickerOption
does seem to set it to the actual currently selected selectedPickerOption
, and the picker behaves as if that was chosen correctly.
What am I possibly missing here?
Upvotes: 2
Views: 2874
Reputation: 8537
The problem occurs as you are modifying selectedPickerOption
which will cause your ContentView to reload whenever the picker changes. Hence, you will pass the selected value as initialPickerOption
. selectedPickerOption
will always be the same like your initial value.
Here is a solution with using local State
in your PickerView and then sync the Binding on Select or don't sync it. I comment the code at these parts
struct PickerPopover: View {
var pickerOptions: [String]
var width: CGFloat
var height: CGFloat
@Binding var showPicker: Bool
@Binding var selectedPickerOption: Int
@State var localState : Int = 0 //<< Here your local State
func selectOption() {
self.selectedPickerOption = localState //<< Sync the binding with the local State
withAnimation {
showPicker.toggle()
}
}
func cancel() {
//<< do nothing here
withAnimation {
showPicker.toggle()
}
}
var body: some View {
VStack {
Picker(
selection: $localState,
label: Text("")
) {
ForEach(0 ..< pickerOptions.count) {
Text(self.pickerOptions[$0])
}
}
.pickerStyle(WheelPickerStyle())
Button(action: cancel) {
Text("Cancel")
}
Button(action: selectOption) {
Text("Select")
}
}
.transition(.move(edge: .bottom))
.onAppear {
self.localState = selectedPickerOption // << set inital value here
}
}
}
Upvotes: 3