【发布时间】:2021-03-24 13:20:30
【问题描述】:
我正在使用 .fullScreenCover 从一个视图转换到另一个视图。呈现的视图有一个导航堆栈,将由几个视图组成。我希望这些视图中的每一个都能够使用 .fullScreenCover 中使用的绑定 isActive 属性来关闭整个堆栈。
我是否需要将此属性绑定到堆栈中的每个视图,或者是否有更简单的方法来执行此操作。我想将此属性添加到导航堆栈的 viewModel 中,但没有成功。这是我想要做的:
struct FirstView: View {
@State var isActive = false
var body: some View {
Text("Press to present Navigation Stack")
.onTapGesture {
isActive = true
}
.fullScreenCover(isPresented: $isActive, content: {
SecondView(isActive: $isActive)
})
}
}
struct SecondView: View {
@StateObject var viewModel: ViewModel = ViewModel()
@Binding var isActive: Bool
@State var showThirdViewIsActive: Bool = false
init(isActive: Binding<Bool>) {
self._isActive = isActive
// somehow get the isActive to my ViewModel but no luck
}
var body: some View {
NavigationView {
Button(action: {
$showThirdViewIsActive = true
}, label: {
Text("Show Third View")
})
Button(action: {
viewModel.dismiss()
}, label: {
Text("Dismiss")
})
NavigationLink(
destination: ThirdView(viewModel: viewModel, isActive: $isActive),
isActive: $showThirdViewIsActive) {}
}
}
}
struct ThirdView: View {
@ObservableObject var viewModel: ViewModel
@Binding var isActive: Bool
init(viewModel: ViewModel, isActive: Binding<Bool>) {
self.viewModel = viewModel
self._isActive = isActive
// somehow get the isActive to my ViewModel but no luck
}
var body: some View {
Button(action: {
viewModel.dismiss()
}, label: {
Text("dismiss")
})
}
}
class ViewModel: ObservableObject {
@Binding var isActive: Bool
func dismiss() {
self.isActive = false
}
}
当然,我可以通过将 isActive 设置为 false 来关闭 SecondView,但我是故意在 ViewModel 中这样做的,因为它不仅适用于这种简单的情况。它可能会在异步调用访问服务器后关闭。
我也刚刚展示了两个视图,但第二个视图中会有 NavigationView,而 NavigationLink 会指向另一个视图,依此类推。它们都将共享相同的 ViewModel。 FirstView 不共享该 ViewModel。
如果可以避免的话,我不想将 isActive 传递给每个视图。我希望能够以某种方式将 isActive 从 SecondView 传递给 viewModel,或者让它成为任何视图都可以访问的某种环境变量。
不确定在我猜测的这种常见情况下的最佳做法是什么。
【问题讨论】:
-
绑定不是在深层视图层次结构中传递控制的可靠方法,请改用基于 ObservableObject 的视图模型。
-
是的,但问题是如何将关闭的 isActive 变量放入可观察的 viewModel