SwiftUI:@EnvironmentObject 与 ViewModifier?
SwiftUI: @EnvironmentObject with ViewModifier?
这是我想做的事情的想法:我的应用程序的导航包含一个列表,它显示点击手势时的视图,该手势由 ViewModifier
触发以执行动画。
简而言之:
MyList > MyViewModifier > MyView
因为我想将一些数据从列表传递到这个层次结构中的最终视图,所以我在考虑使用 @StateObject
/@EnvironmentObject
属性 包装器。但我刚刚意识到我不能像处理 View 那样将 .environmentObject(xx)
传递给 ViewModifier。
这是我目前的代码:
struct TestModel: Identifiable {
var id: Int
var name: String
//@Published var whateverData I would like to fetch later and see appear in other views?
}
class TestObject: ObservableObject {
@Published var elements: [TestModel] = [
TestModel(id: 1, name: "Element 1"),
TestModel(id: 2, name: "Element 2"),
TestModel(id: 3, name: "Element 3")
]
}
struct MyList: View {
@StateObject var testObject = TestObject()
@State var presenting = false
@State var tappedId: Int?
var body: some View {
List(testObject.elements) { element in
Text(element.name)
.onTapGesture {
tappedId = element.id
presenting = true
}
}
.modifier(
MyViewModifier(presented: $presenting, tappedId: tappedId)
// .environmentObject(testObject) ?
)
}
}
struct MyViewModifier: ViewModifier {
@Binding var presented: Bool
var tappedId: Int?
@EnvironmentObject var testObject: TestObject
func body(content: Content) -> some View {
content.overlay(
ZStack {
if presented {
MyView(testObject: _testObject, tappedId: tappedId)
}
}
)
}
}
struct MyView: View {
@EnvironmentObject var testObject: TestObject
var tappedId: Int?
var body: some View {
ZStack {
Color.white
Text(testObject.elements.first(where: { [=10=].id == tappedId })?.name ?? "-")
}
.frame(width: 250, height: 250)
}
}
当然这会在尝试显示 TestView 时引发错误:
No ObservableObject of type TestObject found. A View.environmentObject(_:) for TestObject may be missing as an ancestor of this view.
(仅供参考,我想使用环境对象并将其传递给修饰符然后视图的原因是我可能想在 TestView
中调用 API 当它出现在屏幕,它将获取此对象的更多信息并在 MyList
和 MyView
)
中发送此信息
你在这里有什么建议?感谢您的帮助。
正如评论中所建议的那样,您可以将该对象作为参数传递给您的 ViewModifier
。
另一种选择是在 .modifier()
之后调用 .environmentObject()
,您应该能够从修饰符中读取该对象。
struct MyList: View {
@StateObject var testObject = TestObject()
@State var presenting = false
@State var tappedId: Int?
var body: some View {
List(testObject.elements) { element in
// blah blah
}
.modifier(MyViewModifier(presented: $presenting, tappedId: tappedId))
.environmentObject(testObject)
}
}
这是我想做的事情的想法:我的应用程序的导航包含一个列表,它显示点击手势时的视图,该手势由 ViewModifier
触发以执行动画。
简而言之:
MyList > MyViewModifier > MyView
因为我想将一些数据从列表传递到这个层次结构中的最终视图,所以我在考虑使用 @StateObject
/@EnvironmentObject
属性 包装器。但我刚刚意识到我不能像处理 View 那样将 .environmentObject(xx)
传递给 ViewModifier。
这是我目前的代码:
struct TestModel: Identifiable {
var id: Int
var name: String
//@Published var whateverData I would like to fetch later and see appear in other views?
}
class TestObject: ObservableObject {
@Published var elements: [TestModel] = [
TestModel(id: 1, name: "Element 1"),
TestModel(id: 2, name: "Element 2"),
TestModel(id: 3, name: "Element 3")
]
}
struct MyList: View {
@StateObject var testObject = TestObject()
@State var presenting = false
@State var tappedId: Int?
var body: some View {
List(testObject.elements) { element in
Text(element.name)
.onTapGesture {
tappedId = element.id
presenting = true
}
}
.modifier(
MyViewModifier(presented: $presenting, tappedId: tappedId)
// .environmentObject(testObject) ?
)
}
}
struct MyViewModifier: ViewModifier {
@Binding var presented: Bool
var tappedId: Int?
@EnvironmentObject var testObject: TestObject
func body(content: Content) -> some View {
content.overlay(
ZStack {
if presented {
MyView(testObject: _testObject, tappedId: tappedId)
}
}
)
}
}
struct MyView: View {
@EnvironmentObject var testObject: TestObject
var tappedId: Int?
var body: some View {
ZStack {
Color.white
Text(testObject.elements.first(where: { [=10=].id == tappedId })?.name ?? "-")
}
.frame(width: 250, height: 250)
}
}
当然这会在尝试显示 TestView 时引发错误:
No ObservableObject of type TestObject found. A View.environmentObject(_:) for TestObject may be missing as an ancestor of this view.
(仅供参考,我想使用环境对象并将其传递给修饰符然后视图的原因是我可能想在 TestView
中调用 API 当它出现在屏幕,它将获取此对象的更多信息并在 MyList
和 MyView
)
你在这里有什么建议?感谢您的帮助。
正如评论中所建议的那样,您可以将该对象作为参数传递给您的 ViewModifier
。
另一种选择是在 .modifier()
之后调用 .environmentObject()
,您应该能够从修饰符中读取该对象。
struct MyList: View {
@StateObject var testObject = TestObject()
@State var presenting = false
@State var tappedId: Int?
var body: some View {
List(testObject.elements) { element in
// blah blah
}
.modifier(MyViewModifier(presented: $presenting, tappedId: tappedId))
.environmentObject(testObject)
}
}