EnvrionmentObject 和前面说的StateObjecte功能很类似,唯一不同的是。使用 EnvrionmentObject 包装的属性会在全局范围都可以访问使用。只需在父类中注入到环境变量,后续的子类不需要层层传递。
一起来看看例子
视图一:EnvironmentObjectSample
class EnvrionmentObjectViewModel: ObservableObject {
@Published var languages: [String] = []
init() {
getLanguages()
}
func getLanguages() {
languages.append(contentsOf: ["iOS", "Golang", "Java", "C++", ".Net"])
}
}
struct EnvironmentObjectSample: View {
@StateObject var envrionmentViewModel: EnvrionmentObjectViewModel = EnvrionmentObjectViewModel()
var body: some View {
NavigationView {
List {
ForEach(envrionmentViewModel.languages, id: .self) { item in
NavigationLink {
DetailsView(envrionmentViewModel: envrionmentViewModel, title: item)
} label: {
Text(item)
}
}
}
.navigationTitle("Envrionment Object")
}
.tint(Color.black)
}
}
视图二:DetailsView
struct DetailsView: View {
@ObservedObject var envrionmentViewModel: EnvrionmentObjectViewModel
var title: String
var body: some View {
ZStack {
Color.mint.edgesIgnoringSafeArea(.all)
NavigationLink {
OtherView(envrionmentViewModel: envrionmentViewModel)
} label: {
Text(title)
.font(.headline)
.fontWeight(.semibold)
.foregroundColor(Color.mint)
.padding()
.padding(.horizontal)
.background(Color.white.cornerRadius(25.0))
}
}
}
}
视图三:OtherView
struct OtherView: View {
@ObservedObject var envrionmentViewModel: EnvrionmentObjectViewModel
var body: some View {
ZStack {
LinearGradient(
colors: [Color.gray, Color.blue],
startPoint: .topLeading,
endPoint: .bottomTrailing)
.edgesIgnoringSafeArea(.all)
VStack {
ForEach(envrionmentViewModel.languages, id: .self) { item in
Text(item)
.font(.title2)
.foregroundColor(Color.white)
}
}
}
}
}
上述示例总共三个视图
- EnvironmentObjectSample视图显示一个列表,点击跳转到DetailsView,会把父类(EnvironmentObjectSample)的envrionmentViewModel数据传入到DetailsView中。因为OtherView中显示的是第一个视图中的数据
- DetailsView 视图只需要显示在父类中点击的行的名称
- 显示的内容就是第一个视图的array数据
以上代码写起来很麻烦,其实DetailsViewb ing并不需要使用envrionmentViewModel数据,但是介于需要传递数据到OtherView,所以不得不在DetailsView中去声明一个属性来接收上层到数据传递到下一级
如果有十个View需要使用第一个视图中的数据,那么就需要层层传递。这样真的会很奔溃。但是好在SwiftUI中有一个解决此问题的属性,它叫environmentObject. 其实改造很简单,具体如下:
首先,需要在最上层视图加入一个环境变量,并且把需要传递的数据属性放在里面
NavigationView {
......
}
.environmentObject(envrionmentViewModel)
其次,去掉DetailsView视图中接收上次Array数据的代码
// @ObservedObject var envrionmentViewModel: EnvrionmentObjectViewModel
最后,把@ObservedObject 修饰的变量编变成@EnvironmentObject
// @ObservedObject var envrionmentViewModel: EnvrionmentObjectViewModel
@EnvironmentObject var envrionmentViewModel: EnvrionmentObjectViewModel
以下是全部代码:
import SwiftUI
class EnvrionmentObjectViewModel: ObservableObject {
@Published var languages: [String] = []
init() {
getLanguages()
}
func getLanguages() {
languages.append(contentsOf: ["iOS", "Golang", "Java", "C++", ".Net"])
}
}
struct EnvironmentObjectSample: View {
@StateObject var envrionmentViewModel: EnvrionmentObjectViewModel = EnvrionmentObjectViewModel()
var body: some View {
NavigationView {
List {
ForEach(envrionmentViewModel.languages, id: .self) { item in
NavigationLink {
DetailsView(title: item)
} label: {
Text(item)
}
}
}
.navigationTitle("Envrionment Object")
}
.tint(Color.black)
.environmentObject(envrionmentViewModel)
}
}
struct DetailsView: View {
// @ObservedObject var envrionmentViewModel: EnvrionmentObjectViewModel
var title: String
var body: some View {
ZStack {
Color.mint.edgesIgnoringSafeArea(.all)
NavigationLink {
OtherView()
} label: {
Text(title)
.font(.headline)
.fontWeight(.semibold)
.foregroundColor(Color.mint)
.padding()
.padding(.horizontal)
.background(Color.white.cornerRadius(25.0))
}
}
}
}
struct OtherView: View {
// @ObservedObject var envrionmentViewModel: EnvrionmentObjectViewModel
@EnvironmentObject var envrionmentViewModel: EnvrionmentObjectViewModel
var body: some View {
ZStack {
LinearGradient(
colors: [Color.gray, Color.blue],
startPoint: .topLeading,
endPoint: .bottomTrailing)
.edgesIgnoringSafeArea(.all)
VStack {
ForEach(envrionmentViewModel.languages, id: .self) { item in
Text(item)
.font(.title2)
.foregroundColor(Color.white)
}
}
}
}
}
大家有什么看法呢?欢迎留言讨论。
公众号:RobotPBQ