简体   繁体   中英

Dismiss picker in SwiftUI and reset picker selection to initial value

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?

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
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM