Picker list changed by Toggle

I have a Picker that is effected by following Toggle objects . The picker selects a member from the list but when a subsequent Toggle is used the Picker reverts to line 0 . Both are contained in a VStack which I thought was the issue , but when I isolated the Picker with its own VStack the problem stayed.
Any suggestions are appreciated .

 HStack(alignment:.center,spacing: 40) {
                        Spacer()
                        Text("Date")
                            .font(.title2)
                            .frame(width: 50)
                        Text(date)
                            .font(.title2)
                            .frame(width: 250)
                        Spacer()
                        Picker("User", selection: $selectedUser, content: {
                            ForEach(users,content: { user in
                                Text(user.lastName)
                            })
                        }
                        )
                        .pickerStyle(.wheel)
                    }
                
                HStack(alignment:.center,spacing: 40) {
                    
                    Spacer()
                    Toggle("Biological", isOn: $biological)
                    Spacer()
                    Toggle("Pressure", isOn: $pressure)
                    Spacer()
                    Toggle("Temp", isOn: $temperature)
                    Spacer()
                }
                

@eisenstatjoel

Hi Joel

Without knowing more about what your Users are defined as I’ve defined User as a struct with a few basic properties just for the purposes of the exercise. I’m not sure if your selectedUser is intended to be just a surname, which is a String, or a User.

Have a look at the following code. Maybe it will give you a few clues on what you need to do.

Note that I have added a .tag() modifier which you must include whether you are selecting a User or just the surname of a User.

struct User: Identifiable, Hashable {
    var id = UUID()
    var firstName: String
    var lastName: String
}

struct ContentView: View {
    @State private var biological = false
    @State private var pressure = false
    @State private var temperature = false
    @State private var selectedUser = User(firstName: "", lastName: "")
    let date = "2024/03/13"
    let users = [User(firstName: "Joe", lastName: "Bloggs"),
                 User(firstName: "Fred", lastName: "Nurk"),
                 User(firstName: "Tom", lastName: "Jones"),
                 User(firstName: "Eric", lastName: "DaHalfBee"),
                 User(firstName: "John", lastName: "Smith")
    ]
    var body: some View {
        VStack {
            VStack(alignment:.center,spacing: 40) {
                Spacer()
                Text("Date")
                    .font(.title2)
                    .frame(width: 50)
                Text(date)
                    .font(.title2)
                    .frame(width: 250)
                Spacer()
                Picker("User", selection: $selectedUser) {
                    ForEach(users) { user in
                        Text(user.lastName)
                            .tag(user)
                    }
                }

                .pickerStyle(.wheel)
            }

            HStack(alignment:.center,spacing: 40) {

                Spacer()
                Toggle("Biological", isOn: $biological)
                Spacer()
                Toggle("Pressure", isOn: $pressure)
                Spacer()
                Toggle("Temp", isOn: $temperature)
                Spacer()
            }
        }
        .padding()
    }
}

Note that with this arrangement the selection from the Picker stays irrespective of you changing the toggle.

Thanks Chris , The differences include , HStack to VStack, remove content: ), and add .tag(user). So far no change to Picker being influenced by Toggle after adjusting for these differences.
Removed Picker from the HStack but no change as well . A mystery but likely some minor misplacement of a , or }

That’s a bit odd.

I simplified the way the Picker is configured and changed the HStack to a VStack because the elements you had in the HStack would not fit in the available space horizontally so that means that the Picker was not visible on the device that I was using (iPhone 15 Pro). I changed the VStack back to a HStack and I’ve removed all the .frame specifications. I also changed the HStack spacing parameter to 10 rather than 40 and this is how it now looks on screen. Note: that the date value I used is just arbitrary for the exercise.

Code changed to this:

struct User: Identifiable, Hashable {
    var id = UUID()
    var firstName: String
    var lastName: String
}

struct ContentView: View {
    @State private var biological = false
    @State private var pressure = false
    @State private var temperature = false
    @State private var selectedUser = User(firstName: "", lastName: "")
    let date = "2024/03/13"
    let users = [User(firstName: "Joe", lastName: "Bloggs"),
                 User(firstName: "Fred", lastName: "Nurk"),
                 User(firstName: "Tom", lastName: "Jones"),
                 User(firstName: "Eric", lastName: "DaHalfBee"),
                 User(firstName: "John", lastName: "Smith")
    ]
    var body: some View {
        VStack {
            HStack(alignment:.center, spacing: 10) {
                Spacer()
                Text("Date")

                Text(date)
                    .font(.title2)

                Picker("User", selection: $selectedUser) {
                    ForEach(users) { user in
                        Text(user.lastName)
                            .tag(user)
                    }
                }

                .pickerStyle(.wheel)
            }

            HStack(alignment:.center,spacing: 40) {

                Spacer()
                Toggle("Biological", isOn: $biological)
                Spacer()
                Toggle("Pressure", isOn: $pressure)
                Spacer()
                Toggle("Temp", isOn: $temperature)
                Spacer()
            }
        }
    }
}

If you place that code in a new project and run it, you will see that it works.

Are you saying that when you applied the changes to your project the Picker was still reverting back to the default start up value?

Exactly , here is the whole view ( forest to find the tree) that builds

`//
// AddEditCycleSheet.swift
// SterilizationLogs
//
// Created by Joel Eisenstat on 2024-03-11.
//

import SwiftUI
import SwiftData

struct AddEditCycleSheet: View {

@Environment(\.modelContext) private var context
@Environment(\.dismiss) private var dismiss


var cycle: Cycles
@State  var id: UUID
@State  var date: Date.FormatString.StringLiteralType
@State  var user: String
@State  var biological: Bool
@State  var pressure: Bool
@State  var temperature: Bool
@State  var batchList: [Batches] = [Batches]()
@Query  var users:  [User]


@State var editMode: Bool
@State private var showConfirmation = false
@State private var selectedUser = ""


var body: some View {
    
    ZStack {
        LinearGradient(colors: [.gray,.clear],
                       startPoint: .top, endPoint: .bottom)
        .opacity(0.9)
        .ignoresSafeArea()
        
        //Header
        VStack(alignment:.leading,spacing: 20)  {
            HStack  {
                Spacer()
                Text(editMode ? "Edit Cycle" : "Add Cycle")
                    .font(.title)
                    .foregroundStyle(.white)
                    .padding(.top)
                Spacer()
            }
            HStack(spacing: 0) {
                RoundedRectangle(cornerRadius: 0)
                    .frame( height: 25 )
                    .opacity(0.1)
                    .shadow(radius: 5, x:0 ,y:4)
                    .background(biological ? .green : .red )
                RoundedRectangle(cornerRadius: 0)
                    .frame( height: 25 )
                    .opacity(0.1)
                    .shadow(radius: 5, x:0 ,y:4)
                    .background(pressure ? .green : .red )
                RoundedRectangle(cornerRadius: 0)
                    .frame( height: 25 )
                    .opacity(0.1)
                    .shadow(radius: 5, x:0 ,y:4)
                    .background(temperature ? .green : .red )
            }
            HStack(alignment:.center,spacing: 40) {
               
                Text("Date")
                    .font(.title2)
                    .frame(width: 50)
                    .padding(.leading)
                Text(date)
                    .font(.title2)
                Spacer()
            }
            
            HStack(alignment:.center,spacing: 40) {
              
                Text("Operator")
                    .font(.title2)
                    .frame(width: 100)
                    .padding(.leading)
                Picker("User", selection: $selectedUser) {
                    ForEach(users) { user in
                        Text(user.lastName)
                            .tag(user)
                    }
                }
                    .pickerStyle(.wheel)
                 Spacer()
            }
            HStack(alignment:.center,spacing: 40) {
                
                Spacer()
                Toggle("Biological", isOn: $biological)
                Spacer()
                Toggle("Pressure", isOn: $pressure)
                Spacer()
                Toggle("Temp", isOn: $temperature)
                    .padding(.trailing)
                Spacer()
                }
            
                // Batch List
                VStack {
                    if editMode {               // Only show list if edit / exists
                        Text("Batch List")
                        Spacer()
                        List {
                            ForEach(batchList) { batch in
                                Text(batch.startdate.ISO8601Format())
                            }
                        }
                        listStyle(.plain)
                    } else {
                        Spacer()
                        Spacer()
                    }
                    // Footer with controls
                    ZStack (alignment:.leading)  {
                        RoundedRectangle(cornerRadius: 15)
                            .frame( height: 100 )
                            .opacity(0.1)
                            .shadow(radius: 5, x:0 ,y:4)
                        HStack  {
                            Spacer()
                            Button("Delete") {
                                showConfirmation = true   // delete with confirmation
                            }
                            .buttonStyle(.borderedProminent)
                            .tint(.red)
                            .disabled(editMode == false)
                            .confirmationDialog("Delete record. This is not reversable",
                                                isPresented: $showConfirmation ,
                                                titleVisibility: .visible) {
                                Button("Yes, delete rcord")  {
                                    context.delete(cycle)
                                    dismiss()
                                }
                                Button("No",role: .destructive){}
                                Button("Cancel", role: .cancel){}
                            }
                            Spacer()
                            Spacer()
                            Button("Cancel") {
                                // Do not save any changes or new record
                                dismiss()
                            }
                            .buttonStyle(.borderedProminent)
                            .tint(.gray)
                            Button("Save") {
                                //save record, then dismiss
                                if cycle.user.trimmingCharacters(in: .whitespacesAndNewlines) != "" {  // ok to save
                                    cycle.user = user
                                    cycle.biological = biological
                                    cycle.pressure = pressure
                                    cycle.temperature = temperature
                                    if !editMode {       //new record - editMode = false
                                        withAnimation {
                                            context.insert(cycle)
                                            dismiss()
                                        }
                                    } else {
                                        cycle.startDate = Date.now  //  create date for new record
                                        try? context.save()   //update record - editMode = true
                                        dismiss()
                                    }
                                } else {
                                    // message to add name
                                }
                            }
                            Spacer()
                        }
                        .buttonStyle(.borderedProminent)
                        .tint(.blue)
                        // .disabled(user == "")
                        .padding(.trailing)
                    }
                    
                    
                    .ignoresSafeArea()
                    .onAppear {
                        if editMode  {
                            date = cycle.startDate.ISO8601Format()
                            user = cycle.user
                            biological = cycle.biological
                            pressure = cycle.pressure
                            temperature = cycle.temperature
                            // add batch list
                        } else {
                            user = ""
                            date = Date.now.ISO8601Format()
                            user = ""
                            biological = false
                            pressure = false
                            temperature = false
                    }
                }
            }
        }
        
    }
   
}

}

The dB parts haven’t been tested yet as just trying to set up the interface

Eliminated ( one by one ) components to see if any are the cause, until all that was left were Picker and Toggles. Still defaults to initial Picker - list 0 when the any Toggle is chosen . Would like say it is a bug but experience has shown likely my error - somewhere

Seemed to have it narrowed down to the Toggle variables. When I change the Toggle to a Button the @State private var also moves the Picker to the initial value -

Since you have defined selectedUser as a String, ie:

@State private var selectedUser = “”

change your .tag modifier to

.tag(user.lastName)

Perfect, Thanks again Chris

1 Like