Search code examples
swiftuiviewbuilder

SwiftUI: How do I return to same index with a Picker using SegmentedPickerStyle()


This is just me wrapping my head around ViewBuilders and the new SwiftUI paradigm.

I have a "menu" at the top of my screen along with a couple of buttons.

Menu

If I do a search (tap the magnifying glass), when I return the index always returns to 0 and the first item is selected/displayed. I want to return to the same index it was at when called away. How do I remember the index and reset it?

Here's the Main Menu:

struct TopLevelMenu: View {

/// Toggle to display the Game State (Map) on button tap
@State private var shouldShowWorldMap = false

var body: some View {
NavigationView {
    VStack {
        if shouldShowWorldMap {
            ZStack {
                AnimatedSequence()
                    .modifier(SystemServices())
            } else {
                TopLevelView()

            }
        }
     }
  }
}

struct TopLevelView: View {
   /// Tracks the sheet presentation and current play environment (continent)
    /// mapCenter, display flags, gameOver flat, current continent
    var gameState: GameState = GameState.shared
    /// Handles the game logic, turns, scoring, etc.
    var gameManager: GameManager = GameManager.shared
    /// current game modes: continent, country, capital, grid, about
    @State private var continentIndex = 0

    /// If Help or the World Map is not displayed (triggered by buttons at the top), then this is the Main Display after launch

var body: some View {
    VStack {
        Section {
            Picker(selection: $continentIndex, label: Text("N/A")) {
                ForEach(0 ..< 5) {
                    Text(Continent.continents[$0]).tag($0)
                }
            }
            .pickerStyle(SegmentedPickerStyle())
        }
        SecondLevelView(continentIndex: continentIndex)
            .modifier(SystemServices())
    }
}

}

Normally I would write UIKit code to save the index and restore it, but I'm unsure where such code would go since ViewBuilders aren't cooperative with inlined code. What is accepted practice?


Solution

  • I decided to go with the @AppStorage property wrapper.

    Since the picker options correspond to the raw values of an enum, I added a key to the enum (ContinentType):

    static var key = "ContinentIndex"
    

    Then in the View I replaced:

    @State private var continentIndex = 0
    

    with:

     @AppStorage(ContinentType.key) var selectedContinentIndex = 0
    

    This remembers the last index selected, so I can navigate away to other game modes, but when I return to this view, it remembers which continent I was working with.

    Here's the update in context:

    Section {
        Picker(selection: $selectedContinentIndex, label: Text("Continent")) {
            ForEach(0 ..< 5) {
                Text(ContinentType.continents[$0]).tag($0)
            }
         }
         .pickerStyle(SegmentedPickerStyle())
    }