如何在 SwiftUI 中关闭选项卡视图根视图的呈现视图? [英] How to dismiss a presenting view to the root view of tab view in SwiftUI?

查看:37
本文介绍了如何在 SwiftUI 中关闭选项卡视图根视图的呈现视图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在主页上使用 TabView.假设我有 4 个标签.在第二个选项卡上,我可以使用 NavigationLink 转到另一个视图,然后使用 NavigationLink 转到另外 2 个视图.然后在最新的视图上,有一个按钮可以显示视图,我使用 .fullScreenCover (因为我想全屏显示).

I'm using TabView on my home page. Let's just say I have 4 tabs. On second tab, i can go to another view using NavigationLink and I go to another 2 views using NavigationLink. Then on the latest view, there is a button to present a view and i use .fullScreenCover (since I want to present it full screen).

在呈现视图中,我在 navigationBarItems 的左侧添加了一个 X 标记以关闭.我使用 @Environment(\.presentationMode) var presentationModepresentationMode.wrappedValue.dismiss() 来关闭.但它只是将呈现视图关闭到上一个视图,而实际上我想将它关闭到我的视图的根目录,即我的 TabView 的第二个选项卡.

In the presenting view, I add an X mark on the left side of the navigationBarItems to dismiss. I use @Environment(\.presentationMode) var presentationMode and presentationMode.wrappedValue.dismiss() to dismiss. But it only dismiss the presenting view to the previous view, while actually I want to dismiss it to the root of my view which is the 2nd tab of my TabView.

有没有办法做到这一点?因为我查阅了一些文章,但没有任何相关内容,尤其是在 TabView 上下文中.

Is there a way to do this? Because I have looked up to some articles and nothing relevant especially in TabView context.

我也有一个问题:

  1. 使用 .fullScreenCover 是否正确?或者是否有另一种可能的解决方案,例如以全屏样式呈现模态(如果有任何原因,我也不确定).
  1. Is it a right approach to use .fullScreenCover? Or is there another possible solution for example presenting a modal with full screen style (if there's any cause i'm not sure either).

任何建议将不胜感激,提前谢谢.

Any suggestions will be very appreciated, thankyou in advance.

推荐答案

presentationMode 是一级效果值,即关闭当前显示的一个屏幕.

The presentationMode is one-level effect value, ie changing it you close one currently presented screen.

因此要关闭许多呈现的屏幕,您必须以编程方式实现这一点,就像下面的演示一样.

Thus to close many presented screens you have to implement this programmatically, like in demo below.

可能的方法是使用自定义 EnvironmentKey 将其向下传递到视图层次结构,而无需每个级别视图的紧密耦合(如绑定),并仅在需要时在该级别注入/调用.

The possible approach is to use custom EnvironmentKey to pass it down view hierarchy w/o tight coupling of every level view (like with binding) and inject/call only at that level where needed.

使用 Xcode 12.4/iOS 14.4 测试的演示

Demo tested with Xcode 12.4 / iOS 14.4

struct ContentView: View {
    var body: some View {
        TabView {
            Text("Tab1")
                .tabItem { Image(systemName: "1.square") }
            Tab2RootView()
                .tabItem { Image(systemName: "2.square") }
        }
    }
}

struct Tab2RootView: View {
    @State var toRoot = false
    var body: some View {
        NavigationView {
            Tab2NoteView(level: 0)
                .id(toRoot)          // << reset to root !!
        }
        .environment(\.rewind, $toRoot)        // << inject here !!
    }
}

struct Tab2NoteView: View {
    @Environment(\.rewind) var rewind
    let level: Int

    @State private var showFullScreen = false
    var body: some View {
        VStack {
            Text(level == 0 ? "ROOT" : "Level \(level)")
            NavigationLink("Go Next", destination: Tab2NoteView(level: level + 1))
            Divider()
            Button("Full Screen") { showFullScreen.toggle() }
                .fullScreenCover(isPresented: $showFullScreen,
                                        onDismiss: { rewind.wrappedValue.toggle() }) {
                    Tab2FullScreenView()
                }
        }
    }
}

struct RewindKey: EnvironmentKey {
    static let defaultValue: Binding<Bool> = .constant(false)
}

extension EnvironmentValues {
    var rewind: Binding<Bool> {
        get { self[RewindKey.self] }
        set { self[RewindKey.self] = newValue }
    }
}

struct Tab2FullScreenView: View {
    @Environment(\.presentationMode) var mode

    var body: some View {
        Button("Close") { mode.wrappedValue.dismiss() }
    }
}

这篇关于如何在 SwiftUI 中关闭选项卡视图根视图的呈现视图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆