我有一个带有两个选项卡的SwiftUI TabView,其中一个选项卡使用NavigationLink显示一个子视图.我想要实现的是,当我点击父视图(表示子视图的那个视图)的选项卡项时,它应该go 掉子视图并返回到父视图.

struct ContentView: View {
    var body: some View {
        TabView {
            NavigationView {
                VStack {
                    Text("View1")
                    NavigationLink {
                        Text("Child View")
                    } label: {
                        Text("Go to child view")
                    }
                }
            }
            // when child view is presented, I want when I tap on the tab item view the child view to dismiss. How can I achieve this?
            .tabItem {
                Label("view1", systemImage: "1.circle")
            }
            
            Text("View2")
                .tabItem {
                    Label("view2", systemImage: "2.circle")
                }
        }
    }
}

我try 了各种方法,包括使用.onChange和@Environment(.Presentation模式),但我未能使其按预期工作.

在使用TabView并呈现子视图时,有没有办法在SwiftUI中实现此行为?任何帮助或指导都将不胜感激.

推荐答案

至少有两种方法可以实现你想要的:

  1. 使用.id() API重置NavigationLink.
enum TabSelection {
    case first
    case second
}

private final class ContentViewModel: ObservableObject {
    @Published var tabSelection = TabSelection.first
}

struct ContentView: View {
    @StateObject private var viewModel = ContentViewModel()
    @State private var tab0Id = UUID()

    var body: some View {
        TabView(selection: $viewModel.tabSelection) {
            NavigationView {
                VStack {
                    Text("View1")
                    NavigationLink {
                        Text("Child View")
                    } label: {
                        Text("Go to child view")
                    }
                    .id(tab0Id)
                }
            }
            .tag(TabSelection.first)
            .tabItem {
                Label("view1", systemImage: "1.circle")
            }

            Text("View2")
                .tabItem {
                    Label("view2", systemImage: "2.circle")
                }
                .tag(TabSelection.second)
        }
        .onReceive(viewModel.$tabSelection) { newValue in
            if newValue == .first {
                tab0Id = UUID()
            }
        }
    }
}

结果是:

enter image description here

  1. 将视图模型作为EnvironmentObject注入子视图中:
enum TabSelection {
    case first
    case second
}

private final class ContentViewModel: ObservableObject {
    @Published var tabSelection = TabSelection.first
}

struct ContentView: View {
    @StateObject private var viewModel = ContentViewModel()

    var body: some View {
        TabView(selection: $viewModel.tabSelection) {
            NavigationView {
                VStack {
                    Text("View1")
                    NavigationLink {
                        ChildView()
                    } label: {
                        Text("Go to child view")
                    }
                }
            }
            .tag(TabSelection.first)
            .tabItem {
                Label("view1", systemImage: "1.circle")
            }

            Text("View2")
                .tabItem {
                    Label("view2", systemImage: "2.circle")
                }
                .tag(TabSelection.second)
        }
        .environmentObject(viewModel)
    }
}

struct ChildView: View {
    @Environment(\.dismiss) private var dismiss: DismissAction
    @EnvironmentObject private var rootViewModel: ContentViewModel

    var body: some View {
        Text("Child View")
            .onReceive(rootViewModel.$tabSelection) { newValue in
                if newValue == .first {
                    dismiss()
                }
            }
    }
}

结果是:

enter image description here

EDIT:附注:如果仅当您在第一个选项卡上并点击第一个选项卡项时才需要重置导航,您只需更改onReceive中的逻辑如下:

.onReceive(viewModel.$tabSelection) { [oldValue = viewModel.tabSelection] newValue in
    if oldValue == .first && newValue == .first {
        tab0Id = UUID() // or `dismiss()` if you prefer the second way I described here above
    }
}

结果是:

enter image description here

Swift相关问答推荐

更改正在进行的异步任务的完成(SWIFT并发)(&q;)?

如何防止自动状态恢复,如果应用程序被启动打开特定的文档?

RxSwift .debounce,.throttle用于分页

Swift图表';chartXVisibleDomain挂起或崩溃

如何在visionOS中将模型锚定在用户头部上方?

SwiftUI路径平滑连接两条线

UIBezierPath() 和 DragGesture:连接点创建角而不是曲线

允许为 self 分配新的 struct 值的理由是什么?

防止带有背景的文本扩展到 maxWidth

我如何遵守与演员的协议?

Swift-SceneKit-无法从art.scnassets加载.scn文件

我如何从 UIAlertController 导航到新屏幕(swiftUI)

在 Swift 中从 HTML 生成带有图像的 PDF 而不显示打印界面

在 SwiftUI 中,如何在 UIView 内或作为 UIView 使用 UIHostingController?

如何快速制作虚线?

关闭 UITableViewRowAction

如何在 Swift 中将 UILabel 居中?

自动布局:获取 UIImageView 高度以正确计算单元格高度

修复 Swift 3 中的警告C-style for Statement is deprecated

Swift 的 JSONDecoder 在 JSON 字符串中有多种日期格式?