iOS 15 中的导航 + Tabview + Sheet 损坏

sky*_*ude 10 swiftui swiftui-tabview swiftui-navigationview ios15

看起来 Navigation + TabView + Sheet 在 iOS 15 中被破坏了。

当我这样做时:ContentView -> DetailView -> Bottom Sheet

当底部工作表出现时,Detail视图会自动从堆栈中弹出: https://www.youtube.com/watch? v=gguLptAx0l4

我希望Detail即使底部工作表出现,视图也会保留在那里。有谁知道为什么会发生这种情况以及如何解决它?

这是我的示例代码:

import Combine
import SwiftUI
import RealmSwift

struct ContentView: View {

    var body: some View {
        NavigationView {
            TabView {
                TabItemView(num: 1)
                    .tabItem {
                        Text("One")
                    }
                TabItemView(num: 2)
                    .tabItem {
                        Text("Two")
                    }
            }
        }
    }
}

struct TabItemView: View {

    private let num: Int

    init(num: Int) {
        self.num = num
    }

    var body: some View {
        NavigationLink(destination: DetailView(text: "Detail View \(num)")) {
            Text("Go to Detail View")
        }
    }
}

struct DetailView: View {

    @State private var showingSheet = false

    private let text: String

    init(text: String) {
        self.text = text
    }

    var body: some View {
        Button("Open Sheet") {
            showingSheet.toggle()
        }.sheet(isPresented: $showingSheet) {
            Text("Sheet Text")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,这适用于 iOS 14

更新1:

尝试了 @Sebastian 的建议,NavigationViewTabView. 虽然这修复了导航错误,但它从根本上改变了行为(我不想在 中显示选项卡DetailView)。

还尝试了他使用Introspect设置navigationController.hidesBottomBarWhenPushed = true目的地的建议NavigationLink,但这没有任何作用:

struct ContentView: View {
    
    var body: some View {
        TabView {
            NavigationView {
                TabItemView(num: 1)
            }.tabItem {
                Text("One")
            }
            NavigationView {
                TabItemView(num: 2)
            }.tabItem {
                Text("Two")
            }
        }
    }
}

struct TabItemView: View {
    
    private let num: Int
    
    init(num: Int) {
        self.num = num
    }
    
    var body: some View {
        NavigationLink(destination: DetailView(text: "Detail View \(num)").introspectNavigationController { navigationController in
            navigationController.hidesBottomBarWhenPushed = true
        }) {
            Text("Go to Detail View")
        }
    }
}

struct DetailView: View {
    
    @State private var showingSheet = false
    
    private let text: String
    
    init(text: String) {
        self.text = text
    }
    
    var body: some View {
        Button("Open Sheet") {
            showingSheet.toggle()
        }.sheet(isPresented: $showingSheet) {
            Text("Sheet Text")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Seb*_*ian 1

你需要改变你的嵌套方式TabView& NavigationView。不要TabView在 a 中嵌套多个视图NavigationView,而是使用TabView作为父组件,NavigationView每个选项卡都有一个。

更新后的样子如下ContentView

struct ContentView: View {
    var body: some View {
        TabView {
            NavigationView {
                TabItemView(num: 1)
            }
            .tabItem {
                Text("One")
            }
            
            NavigationView {
                TabItemView(num: 2)
            }
            .tabItem {
                Text("Two")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是有道理的,也是更正确的:选项卡应该始终可见,但您希望在每个选项卡中显示具有不同内容的不同导航堆栈。

它以前的工作并不意味着它更正确——SwiftUI 可能只是在处理意外情况时改变了主意。这,以及在这些情况下缺乏错误消息,是使用试图渲染你扔给它的任何东西的框架的缺点!


如果目标是专门在导航视图上推送新视图时隐藏选项卡(例如,在消息应用程序中点击对话时),则必须使用不同的解决方案。Apple 将该UIViewController.hidesBottomBarWhenPushed属性添加到 UIKit 中以支持此特定用例。

此属性在 UIViewController 上设置,当呈现时,不应显示工具栏。换句话说:不是 UINavigationController 或 UITabBarController,而是您推送到 UINavigationController 上的子 UIViewController。

SwiftUI 本身不支持此属性。您可以使用SwiftUI-Introspect设置它,或者简单地使用 UIKit 编写应用程序的导航结构,并在 SwiftUI 中编写内部视图,并使用UIHostingViewController.