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

Dismiss picker in SwiftUI and reset picker selection to initial value

我正在使用选择器弹出窗口在 SwiftUI 中制作视图。选择一个值并关闭视图时一切正常。

但我需要能够在不设置新选择的值的情况下关闭选择器,并让它恢复到打开时的初始值。

你可以在这里看到代码:


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[[=10=]])
        }
      }
      .pickerStyle(WheelPickerStyle())
      
      Button(action: cancel) {
        Text("Cancel")
      }
      
      Button(action: selectOption) {
        Text("Select")
      }
    }
    .transition(.move(edge: .bottom))
  }
}

我相信 cancel() 函数中的第一行应该可以解决问题 - 如果 selectedPickerOption 设置为 0(或 1 等),这会将选择器专门重置为该索引。

虽然我一直无法动态设置它。我已经尝试传递一个附加值 (intialPickerOption),但重置 selectedPickerOption = initialPickerOption 似乎确实将其设置为当前选择的实际值 selectedPickerOption,并且选择器的行为就像选择正确一样。

我可能在这里遗漏了什么?

问题发生在您修改 selectedPickerOption 时,这将导致您的 ContentView 在选择器更改时重新加载。因此,您会将所选值作为 initialPickerOption 传递。 selectedPickerOption 将始终与您的初始值相同。

这是一个解决方案,在您的 PickerView 中使用本地 State,然后同步 Select 上的 Binding 或不同步它。我在这些部分评论代码

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[[=10=]])
        }
      }
      .pickerStyle(WheelPickerStyle())
      
      Button(action: cancel) {
        Text("Cancel")
      }
      
      Button(action: selectOption) {
        Text("Select")
      }
    }
    .transition(.move(edge: .bottom))
    .onAppear {
        self.localState = selectedPickerOption // << set inital value here
    }
  }
}