Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Bind a Value of a Dictionary to a SwiftUI Control?

I have a class DataPoint which is the value of a dictionary.

DataPoint has a member variable value that I need to bind to a Slider in SwiftUI.

I provide the data class AppData as @Environment Object to SwiftUI, the dictionary holds the instances of class DataPoint.

I fail to manage to bind the DataPoint.value member variable to the SwiftUI Slider value.

These are the relevant code snippets.

The @Published data:

class AppData: ObservableObject {
    @Published var dataPoints: [UUID : DataPoint] = [:] {
    ...
}

The data structure:

class DataPoint: Identifiable {
    var id = UUID()
    var value: Double
}

The SwiftUI view of DataPoints AppDataList:

struct AppDataList: View {
    @EnvironmentObject var appData: AppData

    var body: some View {
        NavigationView {
            List(Array(appData.dataPoints.values)) { dataPoint in
                NavigationLink(destination: DataPointDetail(dataPointID: dataPoint.id)) {
                    Text("\(dataPoint.value)")
                }
            }
    ...
}

The SwiftUI DataPointDetail view that I struggle with, it is referenced from AppDataList:

struct DataPointDetail: View {
    @EnvironmentObject var appData: AppData
    var dataPointID: UUID

    var body: some View {
        HStack(alignment: .top) {
            VStack(alignment: .leading) {
                Text("Data Point Detail")
                Text("\(appData.dataPoints[dataPointID]!.value)")
/* This line */
/* troubles  */
/* me!       */
/*  --->     */ Slider(value: appData.dataPoints[dataPointID]?.value, in: 0...10000)
                Spacer()
                Text("\(appData.dataPoints[dataPointID]!.id)")
            }
        }
    }
}

The root content view:

struct ContentView: View {
    @EnvironmentObject var appData: AppData

    var body: some View {
        VStack {
            if appData.dataPoints.count > 0 {
                AppDataList()
            } else {
                NoDataPoints()
            }
        }
    }
}

The creation of the root content view in SceneDelegate:

        let contentView = ContentView()
            .environmentObject(appData)

I get an error in the editor: Static member 'leading' cannot be used on instance of type 'HorizontalAlignment' and it is in the line of VStack in DataPointDetail view. I believe that it has got nothing to do with the VStack.

Static member 'leading' cannot be used on instance of type 'HorizontalAlignment'

Commenting out the Slider line produces compilable and runnable code.

How would one accomplish this?

like image 787
Jack B. Erger Avatar asked Oct 21 '25 15:10

Jack B. Erger


1 Answers

Most quick solution is to use wrapper binding, as in below snapshot

Slider(value: Binding<Double>(
    get: { self.appData.dataPoints[self.dataPointID]?.value ?? 0 },
    set: { self.appData.dataPoints[self.dataPointID]?.value = $0}), in: 0...10000)
like image 144
Asperi Avatar answered Oct 24 '25 05:10

Asperi