Picker value resets when in a sheet, but works fine in parent View

In the attached minimal reproducing app, the picker in the List works as expected while the one in the sheet resets every time the List view updates (this demo app displays a random byte value that is updated every second).

Can anyone explain why this happens and how to solve the issue, i.e. how can I have a picker in a sheet on a view without the picker getting reset when the parent view receives updates?

Somebody asked the same question here, but it is unanswered, it has different example code: https://www.hackingwithswift.com/forums/swiftui/picker-value-resets-when-in-a-sheet-but-works-fine-in-parent-view/17211

import SwiftUI

@main
struct SwiftUITestApp: App {
  var body: some Scene {
    WindowGroup {
      ContentView()
    }
  }
}

// MARK: - ContentView

struct ContentView: View {
  @State var selectedValue: Int = 0
  @State var isSheetPresented: Bool = false
  @State var randomByte: UInt8 = 0
  
  var body: some View {
    List {
      Text("Frequently updated random byte: \(randomByte)")
      Text("Note how the picker works as expected here:")
      MyPicker()
      Text("But not within a sheet:")
      Button("Select a value inside a sheet") {
        isSheetPresented = true
      }
    }
    .sheet(
      isPresented: $isSheetPresented,
      onDismiss: {
        isSheetPresented = false
      },
      content: {
        List {
          VStack(alignment: .leading, spacing: 16) {
            Text("Select a value close to the bottom of the drop down menu.")
            Text("Then open the drop down menu again.")
            Text("Note that the drop down menu scrolls each time `randomByte` changes.")
          }
          MyPicker()
        }
      }
    )
    .task {
      while true {
        try! await Task.sleep(nanoseconds: 1_000_000_000)
        randomByte = UInt8.random(in: .min ... .max)
      }
    }
  }
}

// MARK: MyPicker

struct MyPicker: View {
  @State var selectedValue: Int = 0
  var body: some View {
    Picker("Value", selection: $selectedValue) {
      ForEach(0..<100, id: \.self) { value in
        Text("\(value)").tag(value)
      }
    }
    .onChange(of: selectedValue) { _ in
      print("•••• selectedValue", selectedValue)
    }
  }
}

// MARK: Preview

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}
  • You aren't using the selectedValue variable in ContentView. So nobody knows how the selectedValue variable in MyPicker is supposed to affect ContentView. If the selectedValue variable in MyPicker is supposed to affect ContentView, then make it Binding.

  • Isn't that unrelated to the issue I described? (The selectedValue doesn't need to affect ContentView in order to demonstrate the issue.) Here is the issue again: While the sheet is open, and I try to scroll through the picke's items, it is impossible to reach to the bottom, because it will scroll back to the top once every second, each time the randomByte is updated. Why is this, and how can I make the picker in the sheet not reset/scroll back to the top every time randomByte is updated?

Add a Comment