如何使用 SwiftUI 关闭多个视图
Posted
技术标签:
【中文标题】如何使用 SwiftUI 关闭多个视图【英文标题】:How to dismiss multiple view with SwiftUI 【发布时间】:2019-12-24 09:06:32 【问题描述】:import SwiftUI
struct ContentView: View
@State var showSecond = false
@State var showThird = false
var body: some View
VStack(spacing: 50)
Text("FirstView")
Button("to SecondView")
self.showSecond = true
.sheet(isPresented: $showSecond)
VStack(spacing: 50)
Text("SecondView")
Button("to ThirdView")
self.showThird = true
.sheet(isPresented: self.$showThird)
VStack(spacing: 50)
Text("ThirdView")
Button("back")
self.showThird = false
Button("back to FirstView")
self.showThird = false
self.showSecond = false
Button("back")
self.showSecond = false
struct ContentView_Previews: PreviewProvider
static var previews: some View
ContentView()
上面的代码从FirstView过渡到SecondView,从SecondView过渡到ThirdView。而SecondView 和ThirdView 中的“返回”按钮正常返回上一屏。
但是,如果您在 ThirdView 中点击“返回 FirstView”按钮,将显示 SecondView 而不会返回 FirstView。而且这个操作之后,当你点击SecondView的“返回”按钮时,它并没有返回到FirstView。
如何从 ThirdView 直接返回到 FirstView?
2020 年 2 月 19 日添加
我已经根据答案添加了解决方案代码。
解决方案 1:基于 Asperi 的 A 计划。
struct ContentView: View
@State var showSecond = false
@State var showThird = false
var body: some View
VStack(spacing: 50)
Text("FirstView")
Button("to SecondView")
self.showSecond = true
.sheet(isPresented: $showSecond)
VStack(spacing: 50)
Text("SecondView")
Button("to ThirdView")
self.showThird = true
.sheet(isPresented: self.$showThird)
VStack(spacing: 50)
Text("ThirdView")
Button("back")
self.showThird = false
Button("back to FirstView")
DispatchQueue.main.async
self.showThird = false
DispatchQueue.main.async
self.showSecond = false
Button("back")
self.showSecond = false
解决方案 2:基于 Asperi 的 B 计划。
struct ContentView: View
@State var showSecond = false
@State var showThird = false
@State var backToFirst = false
var body: some View
VStack(spacing: 50)
Text("FirstView")
Button("to SecondView")
self.showSecond = true
.sheet(isPresented: $showSecond)
VStack(spacing: 50)
Text("SecondView")
Button("to ThirdView")
self.showThird = true
.sheet(isPresented: self.$showThird, onDismiss:
if self.backToFirst
self.showSecond = false
)
VStack(spacing: 50)
Text("ThirdView")
Button("back")
self.showThird = false
self.backToFirst = false
Button("back to FirstView")
self.showThird = false
self.backToFirst = true
Button("back")
self.showSecond = false
解决方案 3:根据 Joseph 的建议。
struct ContentView: View
@State var showSecond = false
@State var showThird = false
var body: some View
GeometryReader geometry in
ZStack
VStack(spacing: 50)
Text("FirstView")
Button("to SecondView")
self.showSecond = true
.frame(width: geometry.size.width, height: geometry.size.height)
.background(Rectangle().foregroundColor(.white))
if self.showSecond
VStack(spacing: 50)
Text("SecondView")
Button("to ThirdView")
self.showThird = true
Button("back")
self.showSecond = false
.frame(width: geometry.size.width, height: geometry.size.height)
.background(Rectangle().foregroundColor(.white))
if self.showThird
VStack(spacing: 50)
Text("ThirdView")
Button("back")
self.showThird = false
Button("back to FirstView")
self.showThird = false
self.showSecond = false
.frame(width: geometry.size.width, height: geometry.size.height)
.background(Rectangle().foregroundColor(.white))
【问题讨论】:
【参考方案1】:目前直接没有办法(而且 IMO 永远不会 - 这是两个模态会话)...我发现了两种可能值得考虑的方法:
A.从一个地方顺序关闭
Button("back to FirstView")
DispatchQueue.main.async
self.showThird = false
DispatchQueue.main.async
self.showSecond = false
B.从不同的地方顺序关闭
.sheet(isPresented: self.$showThird, onDismiss:
self.showSecond = false // with some additional condition for forced back
)...
...
Button("back to FirstView")
self.showThird = false
【讨论】:
感谢您的建议!我已经尝试过你的建议。 A计划没有效果。但是,当我使用“DispatchQueue.main.asyncAfter (deadline: .now () + 0.01)”而不是“DispatchQueue.main.async”时,它现在按建议工作。 B计划按建议进行。当我使用这个计划时,我需要在“.onDismiss”处添加一个可以确定是否返回FirstView的新状态变量。无论如何,这两个计划都是逐步过渡到返回FirstView,而不是直接过渡。我想等待对方的解决方案。 我又检查了一遍。 planA 使用如图所示的代码。当我之前检查它时,我在设置 showThird 之前省略了 DispatchQueue。我已根据此建议向问题区域添加了代码。【参考方案2】:另一个/cough/“解决方案” - 可能是稍微不同的场景 - 但无论如何:
struct ContentView: View
var body: some View
NavigationView
NavigationLink(destination: SecondView())
Text("Show Second View")
.font(.largeTitle)
.navigationViewStyle(StackNavigationViewStyle())
struct SecondView: View
@Environment(\.presentationMode) var presentationMode
@State private var showModal = false
var body: some View
GeometryReader geometry in
ZStack
Rectangle()
.foregroundColor(.gray)
.frame(width: geometry.size.width, height: geometry.size.height)
Button(action:
withAnimation
self.showModal.toggle()
)
Text("Show Third View")
.font(.largeTitle)
.foregroundColor(.white)
if self.showModal
VStack
Button(action:
self.presentationMode.wrappedValue.dismiss()
)
Text("Show First View")
.font(.largeTitle)
.foregroundColor(.white)
.frame(width: geometry.size.width, height: geometry.size.height)
.background(Rectangle().foregroundColor(.orange))
.transition(.move(edge: .trailing))
.frame(width: geometry.size.width, height: geometry.size.height)
【讨论】:
Z-stacking 多个基于@State
布尔值渲染的动画视图可能是一种使合成展开后“深度”连续几层的方法。它并不完全优雅,但是......是的
感谢您的建议!您关于使用 zstack 覆盖视图的建议非常有帮助。如果我们不关心使用工作表为模态转换设置动画,此方法非常有效。我已根据此建议将代码添加到问题区域。【参考方案3】:
Asperi 的解决方案适用于同时关闭两个屏幕,但不适用于更多屏幕。在这种情况下,我们需要在两种方法中添加DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300))
,如下所示:
self.showFourth = false
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300))
self.showThird = false
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300))
self.showSecond = false
.milliseconds(200)
还不够。
【讨论】:
以上是关于如何使用 SwiftUI 关闭多个视图的主要内容,如果未能解决你的问题,请参考以下文章
单击搜索栏时如何显示单独的视图? [SwiftUI] [关闭]
SwiftUI:如何将 NSManagedObjectContext 传递到多个视图模型中