Home > other >  How to store array of State variables in swiftui?
How to store array of State variables in swiftui?

Time:12-31

I have some buttons and I want to apply different background color on selection for each button but I want to maintain the state within the array for selection and deselection. I have created a class for a single object by confirming the ObservableObject. Then I am creating the array of the the same objects and trying to store it with in a StateObject variable but it's showing an error like "Generic struct 'StateObject' requires that '[TimeSlot]' conform to 'ObservableObject'". How can I achieve it.

    import SwiftUI

class TimeSlot: ObservableObject {
    @State var timelot: String
    @State var state: Bool
    
    init(timelot: String, state: Bool) {
        self.timelot = timelot
        self.state = state
    }
}

struct DateTimeSelectionView: View {
    
    
    
    @StateObject var timeSlots = [
        TimeSlot(timelot: "06:30", state: false),
        TimeSlot(timelot: "07:30", state: false),
        TimeSlot(timelot: "08:00", state: false),
        TimeSlot(timelot: "08:30", state: false)
    ]
    
    
    
    var body: some View {
        ScrollView {
            
            VStack(alignment: .leading) {
                Text("Select Time:")
                    .multilineTextAlignment(.leading)
                    .font(.system(size: 20, weight: .medium, design: .default))
                                        .foregroundColor(AppTheme.appThemeOrange)
                
                VStack(alignment: .leading, spacing: 15) {
                    HStack {
                        ForEach(timeSlots) { index in
                            Button {
                                timeSlots[index].state.toggle()
                            } label: {
                                Text("\(timeSlots[index].timelot) PM")
                                    .foregroundColor(.white)
                                    .font(.system(size: 16, weight: .medium, design: .default))
                            }.frame(width: 74)
                                .padding(.horizontal, 6)
                                    .padding(.vertical, 10)
                                    .background(AppTheme.appThemeBlue)
                                    .cornerRadius(2)
                        }
                    }
                    
                    
                }
            }.padding(.horizontal, 10)
        }
    }
}

struct DateTimeSelectionView_Previews: PreviewProvider {
    static var previews: some View {
        DateTimeSelectionView()
    }
}

CodePudding user response:

There are a lot of issues in the data handling here. Try this commented code:

// this is a model container so no need for observable object or class implementation
struct TimeSlot: Hashable {
    // @State is only valid in Views
    var timelot: String
    var state: Bool
    // initializer is unnecessary
}

struct DateTimeSelectionView: View {
    // a collection of models should be @State
    @State private var timeSlots = [
        TimeSlot(timelot: "06:30", state: false),
        TimeSlot(timelot: "07:30", state: false),
        TimeSlot(timelot: "08:00", state: false),
        TimeSlot(timelot: "08:30", state: false)
    ]
    
    var body: some View {
        ScrollView {
            
            VStack(alignment: .leading) {
                Text("Select Time:")
                    .multilineTextAlignment(.leading)
                    .font(.system(size: 20, weight: .medium, design: .default))
                
                VStack(alignment: .leading, spacing: 15) {
                    HStack {
                        // if you want to change the item inside the ForEach loop
                        // you need a binding to it
                        // additionally you need to set the id
                        ForEach($timeSlots, id: \.self) { $slot in
                            // inside the loop you get a binding to the item itself
                            // use it here to display and manipulate it
                            Button {
                                slot.state.toggle()
                            } label: {
                                Text("\(slot.timelot) PM")
                                // added this to help visualize the state
                                    .foregroundColor(slot.state ? .blue : .red)
                                    .font(.system(size: 16, weight: .medium, design: .default))
                            }.frame(width: 74)
                                .padding(.horizontal, 6)
                                .padding(.vertical, 10)
                                .cornerRadius(2)
                        }
                    }
                }
            }.padding(.horizontal, 10)
        }
    }
}
  • Related