在SwiftUI中,TabView必须是根视图。因此,您不能使用NavigationLink导航到TabView。假设我的应用程序中有四个屏幕。
屏幕A是包含屏幕B和屏幕C的TabView。屏幕B是具有NavigationLink的列表,可带您进入列表项的详细信息(屏幕D)屏幕C是一个信息视图(在问题中并不重要)屏幕D是列表项详细信息屏幕,您必须首先导航到屏幕b才能到达此处。屏幕D,但是,有一个按钮,应该带您进入屏幕A。
屏幕D如何导航到根屏幕(屏幕A)的两个级别?
我做了这样的把戏,为我工作。
在SceneDelegate.swift中,我修改了自动生成的代码。
let contentView = ContentView()
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
// Trick here.
let nav = UINavigationController(
rootViewController: UIHostingController(rootView: contentView)
)
// I embedded this host controller inside UINavigationController
// window.rootViewController = UIHostingController(rootView: contentView)
window.rootViewController = nav
self.window = window
window.makeKeyAndVisible()
}
注:我希望将TabView
嵌入NavigationView
内可以完成相同的工作,但是没有用,这是执行此技巧的原因。
我假设,contentView
是要弹出到的视图(一个包含TabView)
然后在从该视图导航的任何视图中,都可以调用
extension View {
func popToRoot() {
guard let rootNav = UIApplication.shared.windows.first?.rootViewController as? UINavigationController else { return }
rootNav.popToRootViewController(animated: true)
}
}
// Assume you eventually came to this view.
struct DummyDetailView: View {
var body: some View {
Text("DetailView")
.navigationBarItems(trailing:
Button("Pop to root view") {
self.popToRoot()
}
)
}
}
“弹出”到根视图的一种有效方法是利用用于导航的isDetailLink
上的NavigationLink
修饰符。
默认情况下,isDetailLink
为true
。该修饰符用于各种视图容器,例如在iPad上,详细视图将显示在右侧。
将isDetailLink
设置为false
意味着该视图将被推入NavigationView
堆栈的顶部,也可以将其推下。
[在isDetailLink
上将NavigationLink
设置为false的同时,将isActive
绑定传递到每个子目标视图。当要弹出到根视图时,将值设置为false
,它将弹出所有内容:
import SwiftUI
struct ScreenA: View {
@State var isActive : Bool = false
var body: some View {
NavigationView {
NavigationLink(
destination: ScreenB(rootIsActive: self.$isActive),
isActive: self.$isActive
) {
Text("ScreenA")
}
.isDetailLink(false)
.navigationBarTitle("Screen A")
}
}
}
struct ScreenB: View {
@Binding var rootIsActive : Bool
var body: some View {
NavigationLink(destination: ScreenD(shouldPopToRootView: self.$rootIsActive)) {
Text("Next screen")
}
.isDetailLink(false)
.navigationBarTitle("Screen B")
}
}
struct ScreenD: View {
@Binding var shouldPopToRootView : Bool
var body: some View {
VStack {
Text("Last Screen")
Button (action: { self.shouldPopToRootView = false } ){
Text("Pop to root")
}
}.navigationBarTitle("Screen D")
}
}