In swiftUI it's fairly simple to create single-use views with their according States embedded in an associated view-model. But how can I use the e.g. custom textfield of view1, which is embedded in a more complex view2, in view3 which is the final view? I know that I could pass the textfield's text of view1 as binding to view2 and then to view3. But as soon as the UI gets complex a lot of bindings need to bee passed, especially if there are a lot of intermediate views. How could I reuse view1 without passing it's textfield text state to every intermediate view, and how could this ideally be implemented into the view-model of view3?
Simple example structure:
View1:
struct SwiftUIView3: View {
@Binding var textInTextField: String
var body: some View {
TextField("Test", text: $textInTextField)
}
}
View2:
struct SwiftUIView2: View {
@Binding var textInTextField: String
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 15)
.frame(height: 200)
.foregroundColor(.blue)
SwiftUIView3(textInTextField: $textInTextField)
}
}
}
View3:
struct ContentView: View {
@State private var textInTextField = ""
var body: some View {
VStack {
SwiftUIView2(textInTextField: $textInTextField)
Text(textInTextField)
}
}
}
Here is possible solution. Tested with Xcode 11.4 / iOS 13.4
The idea is to use view model injected as environment object into sub-hierarchy, so in any level subview can extract it and use, the top-level view will be updated correspondingly `cause it holds this view model as observed object.
struct SwiftUIView3: View {
@EnvironmentObject var eo: TextViewModel // << auto-associated
var body: some View {
TextField("Test", text: $eo.textInTextField)
}
}
struct SwiftUIView2: View {
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 15)
.frame(height: 200)
.foregroundColor(.blue)
SwiftUIView3() // << nothing to pass
}
}
}
class TextViewModel: ObservableObject {
@Published var textInTextField = ""
}
struct ContentView: View {
@ObservedObject private var vm = TextViewModel()
var body: some View {
VStack {
SwiftUIView2() // << nothing to pass
Text(vm.textInTextField)
}.environmentObject(vm) // << inject into hierarchy
}
}