切换标签时,TabView重置导航堆栈

Cas*_*gen 15 swiftui

我有一个简单的TabView:

TabView {
    NavigationView {
        VStack {
            NavigationLink(destination: Text("Detail")) {
                Text("Go to detail")
            }
        }
    }
        .tabItem { Text("First") }
        .tag(0)
    Text("Second View")
        .tabItem { Text("Second") }
        .tag(1)
}
Run Code Online (Sandbox Code Playgroud)

当我转到选项卡1上的详细信息视图时,切换到选项卡2,然后再切换回选项卡1,我假设将返回到详细信息视图(iOS中随处可见的基本UX)。而是重置为选项卡1的根视图。

由于SwiftUI并不希望立即提供支持,因此该如何解决呢?

Cas*_*gen 8

这里不太明显的解决方案是实际上不使用SwiftUI。为了获得UIKit的行为,我将UIKit包裹UITabBarController在SwiftUI UIViewControllerRepresentable中,例如以下示例:https : //developer.apple.com/tutorials/swiftui/interface-with-uikit

我在这里展示了一个基本的实现。完整的最新实现在github上:https : //gist.github.com/Amzd/2eb5b941865e8c5cccf149e6e07c8810

将UIKit UITabBarController包装在SwiftUI视图中:

struct UIKitTabView: View {
    var viewControllers: [UIHostingController<AnyView>]

    init(_ tabs: [Tab]) {
        self.viewControllers = tabs.map {
            let host = UIHostingController(rootView: $0.view)
            host.tabBarItem = $0.barItem
            return host
        }
    }

    var body: some View {
        TabBarController(controllers: viewControllers)
            .edgesIgnoringSafeArea(.all)
    }

    struct Tab {
        var view: AnyView
        var barItem: UITabBarItem

        init<V: View>(view: V, barItem: UITabBarItem) {
            self.view = AnyView(view)
            self.barItem = barItem
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
struct TabBarController: UIViewControllerRepresentable {
    var controllers: [UIViewController]

    func makeUIViewController(context: Context) -> UITabBarController {
        let tabBarController = UITabBarController()
        tabBarController.viewControllers = controllers
        return tabBarController
    }
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

struct ExampleView: View {
    @State var text: String = ""

    var body: some View {
        UIKitTabView([
            UIKitTabView.Tab(
                view: NavView(), 
                barItem: UITabBarItem(title: "First", image: nil, selectedImage: nil)
            ),
            UIKitTabView.Tab(
                view: Text("Second View"), 
                barItem: UITabBarItem(title: "Second", image: nil, selectedImage: nil)
            )
        ])
    }
}

struct NavView: View {
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: Text("This page stays when you switch back and forth between tabs (as expected on iOS)")) {
                    Text("Go to detail")
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Rus*_*ian 5

这是一个简单的示例,说明如何使用根目录下的项目列表保留导航堆栈的状态:

struct ContentView: View {

    var body: some View {

        TabView {

            Text("First tab")
                .tabItem { Image(systemName: "1.square.fill"); Text("First") }
                .tag(0)

            SecondTabView()
                .tabItem { Image(systemName: "2.square.fill"); Text("Second") }
                .tag(1)
        }
    }
}

struct SecondTabView: View {

    private struct ListItem: Identifiable {
        var id = UUID()
        let title: String
    }

    private let items = (1...10).map { ListItem(title: "Item #\($0)") }

    @State var selectedItemIndex: Int? = nil

    var body: some View {

        NavigationView {
            List(self.items.indices) { index in
                NavigationLink(destination:  Text(self.items[index].title),
                               tag: index,
                               selection: self.$selectedItemIndex) {
                    Text(self.items[index].title)
                }
            }
            .navigationBarTitle("Second tab", displayMode: .inline)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)