Reputation: 2598
I'm trying to reusable View and I added it on ContentView
This is my Child View
struct VStackView: View {
@Binding var spacing: Double
@Binding var alignmentIndex: Int
@Binding var elementsCount: Int
private let alignments: [HorizontalAlignment] = [.leading, .center, .trailing]
var body: some View {
VStack(alignment: self.alignments[alignmentIndex], spacing: CGFloat(spacing)) {
ForEach(0..<elementsCount) {
Text("\($0)th View")
}
}
}
}
and This is SuperView
Superview has Controls like Stepper, Slider, Picker that adjust values of VStack (alignment, spacing etc)
and I want to show the result depending on that values. but Child View is not changed
struct LayoutView: View {
private let layout: StackLayout
@State private var spacing = 0.0
@State private var alignmentIndex = 0
@State private var alignment: HorizontalAlignment = .leading
@State private var elementsCount: Int = 0
private let alignmentsString = [".leading", ".center", ".trailing"]
private let minValue = 0.0
private let maxValue = 100.0
init(_ layout: StackLayout) {
self.layout = layout
}
var body: some View {
NavigationView {
Form {
Section(header: Text("Controls")) {
VStack(alignment: .leading) {
Text("Spacing: \(Int(spacing))").font(.caption)
HStack {
Text("\(Int(minValue))")
Slider(value: $spacing, in: minValue...maxValue, step: 1)
Text("\(Int(maxValue))")
}
Divider()
Picker("alignment", selection: $alignmentIndex) {
ForEach(0..<self.alignmentsString.count) {
Text("\(self.alignmentsString[$0])")
}
}.pickerStyle(SegmentedPickerStyle())
Divider()
Stepper(value: $elementsCount, in: 0...10) {
Text("Element Count: \(elementsCount)")
}
}
}
VStackView(spacing: $spacing, alignmentIndex: $alignmentIndex, elementsCount: $elementsCount)
}
.navigationBarTitle(Text(layout.rawValue), displayMode: .inline)
}
}
}
I also search google and they recommend @EnviornmentObject. if that is correct, when to use @Binding property wrapper.
Isn't it two way binding properties?
Upvotes: 0
Views: 628
Reputation: 199
Simply speaking you can use @Binding, when you want to share data in two places.
@Observable or @environmetobject is to be used, when you want to share your data in multiple views.
Your ForEach Loop in the VStackView generates a problem, because Swiftui does not know how it can identify each of your items uniquely so it does not know how to update them, when values change.
Append your code like this:
ForEach(0..<elementsCount, id: \.self) {
Text("\($0)th View")
}
Upvotes: 1