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