简体   繁体   English

SwiftUI:不同视图之间的数据共享

[英]SwiftUI: Data sharing between separate views

What is the best practice to share variables between views?在视图之间共享变量的最佳做法是什么? My app has only one view.我的应用程序只有一个视图。 But as it gets more and more complicated, I think I should separate it into several views.但是随着它变得越来越复杂,我认为我应该将它分成几个视图。 Also to separate the methods.还要分开方法。 I started with something like this:我从这样的事情开始:

struct ContentView: View {
    @State var str: String = "String"
    var body: some View {
        VStack(alignment: .leading) {
            Text(str)
            TextField("Input", text: $str)
            Button("button", action: { doSomething() })
        }.padding()
    }
    func doSomething() {
        str = str + " " + str
    }
}

And want to go there:并想 go 那里:

class GlobalVars: ObservableObject {
    @Published var str: String = "Initial String"
}
struct ContentView: View {
    @ObservedObject var globalvars = GlobalVars()
    var body: some View {
        VStack(alignment: .leading) {
            DisplayView()
            EditView()
            ControlView()
        }.padding()
    }
}
struct DisplayView: View {
    @Binding var str:  String
    var body: some View {
        Text(self.globalvars.str)
    }
}
struct EditView: View {
    @Binding var str:  String
    var body: some View {
        TextField("Input", text: self.$str)
    }
}
struct ControlView: View {
    @Binding var str:  String
    var body: some View {
        Button("button", action: { doSomething() })
    }
}
func doSomething() {
    @Binding var str:  String
    self.str = self.str + " " + self.str
}

I tried with @Published, @ObservedObject and @Binding.我尝试使用@Published、@ObservedObject 和@Binding。 But don't get it.但不明白。 Thank you for any pointer in advance.感谢您提前提供任何指示。

There are a number of ways to approach this.有很多方法可以解决这个问题。

My choice would probably be passing the binding just to the variable that you need access to.我的选择可能是将绑定仅传递给您需要访问的变量。 That might look like this:这可能看起来像这样:

class GlobalVars: ObservableObject {
    @Published var str: String = "Initial String"
}
struct ContentView: View {
    @ObservedObject var globalvars = GlobalVars()
    var body: some View {
        VStack(alignment: .leading) {
            DisplayView(str: globalvars.str) //don't need a binding here since it doesn't get modified
            EditView(str: $globalvars.str)
            ControlView(str: $globalvars.str)
        }.padding()
    }
}
struct DisplayView: View {
    var str:  String //don't need a binding here since it doesn't get modified
    var body: some View {
        Text(str)
    }
}
struct EditView: View {
    @Binding var str:  String
    var body: some View {
        TextField("Input", text: $str)
    }
}
struct ControlView: View {
    @Binding var str:  String
    var body: some View {
        Button("button", action: { doSomething() })
    }
    
    func doSomething() {
        str = str + " " + str
    }
}

Note that now in ContentView , there's a parameter passed to each of the subviews, containing a binding (using the $ sign) to the GlobalVars str property.请注意,现在在ContentView中,有一个参数传递给每个子视图,其中包含到GlobalVars str属性的绑定(使用$符号)。

Also, doSomething got moved into the body of ControlView此外, doSomething被移入ControlView的主体


You could also use EnvironmentObject to handle this.您也可以使用 EnvironmentObject 来处理这个问题。 I'm personally not as big of a fan of this approach because I'd rather see explicitly where my parameters are going.我个人不太喜欢这种方法,因为我宁愿明确地看到我的参数的去向。 It also gives the subviews access to the entire ObservableObject, which isn't really necessary.它还使子视图可以访问整个 ObservableObject,这并不是必需的。 But, it shows you the principal:但是,它向您展示了校长:

class GlobalVars: ObservableObject {
    @Published var str: String = "Initial String"
}
struct ContentView: View {
    @ObservedObject var globalvars = GlobalVars()
    var body: some View {
        VStack(alignment: .leading) {
            DisplayView()
            EditView()
            ControlView()
        }.padding()
        .environmentObject(globalvars)
    }
}
struct DisplayView: View {
    @EnvironmentObject var globalvars : GlobalVars
    var body: some View {
        Text(globalvars.str)
    }
}
struct EditView: View {
    @EnvironmentObject var globalvars : GlobalVars
    var body: some View {
        TextField("Input", text: $globalvars.str)
    }
}
struct ControlView: View {
    @EnvironmentObject var globalvars : GlobalVars
    var body: some View {
        Button("button", action: { doSomething() })
    }
    
    func doSomething() {
        globalvars.str = globalvars.str + " " + globalvars.str
    }
}

Note that now, globalvars is passed to the children by being placed in the view hierarchy with .environmentObject .请注意,现在, globalvars通过放置在具有.environmentObject的视图层次结构中传递给子项。 Each subview has access to it by declaring a property of @EnvironmentObject var globalvars: GlobalVars每个子视图都可以通过声明@EnvironmentObject var globalvars: GlobalVars


You could also do kind of a hybrid model where you explicitly pass the ObservableObject as a parameter to the child view:您还可以做一种混合 model ,其中您将 ObservableObject 作为参数显式传递给子视图:

struct ContentView: View {
    @ObservedObject var globalvars = GlobalVars()
    var body: some View {
        VStack(alignment: .leading) {
            DisplayView(globalvars: globalvars)
        }.padding()
        .environmentObject(globalvars)
    }
}

struct DisplayView: View {
    @ObservedObject var globalvars : GlobalVars
    var body: some View {
        Text(globalvars.str)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM