简体   繁体   English

关闭 SwiftUI 中的选择器并将选择器选择重置为初始值

[英]Dismiss picker in SwiftUI and reset picker selection to initial value

I am making a view in SwiftUI with a picker-popover.我正在使用选择器弹出窗口在 SwiftUI 中进行查看。 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.但是我需要能够在不设置新选择的值的情况下关闭选择器,并将其 go 恢复为打开时的初始值。

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.我相信cancel() function 中的第一行应该可以解决问题 - 如果selectedPickerOption设置为 0(或 1 等),它将专门将选择器重置为该索引。

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.我尝试传入一个附加值( intialPickerOption ),但重置selectedPickerOption = initialPickerOption似乎确实将其设置为当前实际选择的selectedPickerOption ,并且选择器的行为就像选择正确一样。

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.当您修改selectedPickerOption时会出现问题,这将导致您的 ContentView 在选择器更改时重新加载。 Hence, you will pass the selected value as initialPickerOption .因此,您会将所选值作为initialPickerOption传递。 selectedPickerOption will always be the same like your initial value. selectedPickerOption将始终与您的初始值相同。

Here is a solution with using local State in your PickerView and then sync the Binding on Select or don't sync it.这是在您的 PickerView 中使用本地State的解决方案,然后在 Select 上同步绑定或不同步它。 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
    }
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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