与confirmationDialog或alert交互会导致父视图弹出。

4
当你浏览并打开确认对话框时。当你选择“是”,“否”或“取消”时,应用程序所在的页面将被取消,并带您回到前一页的表单。
我们也发现这种情况也发生在警报中。 这是一个非常简单的应用程序结构,顶级选项卡,然后是一个菜单,链接到子页面。
以下是该错误的快速演示: Bug演示 我们编写了一个示例应用程序来演示此问题。如何在维护应用程序结构的同时防止这种情况发生?
import SwiftUI

@main
struct testApp: App {
    var body: some Scene {
        WindowGroup {
            NavigationView {
                TabView() {
                    Form {
                        NavigationLink(destination: SubPage()) {
                            Image(systemName: "clock")
                            Text("Sub Page")
                        }
                        // This is where more menu options would be
                    }
                    .tag(1)
                    .tabItem {
                        Image(systemName: "square.grid.2x2")
                        Text("Tab 1")
                    }
                    // This is where more tab pages would be
                }
            }
        }
    }
}

struct SubPage: View {
    @State private var confirmDialogVisible = false
    
    var body: some View {
        VStack {
            Button{
                confirmDialogVisible = true
            } label: {
                Text("popup")
            }
        }
        .confirmationDialog("Confirm?", isPresented: $confirmDialogVisible) {
            Button("Yes") {
                print("yes")
            }
            Button("No", role: .destructive) {
                print("no")
            }
        }
    }
}

我们正在使用 XCode 14.1,并在 iOS 16.1 上运行。


2
NavigationView 中的 TabView 会引起许多问题。苹果不希望 TabView 按照这种方式工作,这在指南中有提到。 - lorem ipsum
这是一个非常好的评论 @loremipsum 我们这样做是为了在选项卡视图之间保留具有标题和图标的顶部导航。 还有其他方法可以实现吗? - Tom Banister
在TabView中使用NavigationView,每个选项卡具有相同的导航标题。 - Ptit Xav
2个回答

1

我通常使用ViewModifier来保持选项卡之间的一致性。一个用于选项卡的根部,另一个用于其子级。

///Modifier that uses `ToolbarViewModifier` and includes a `NavigationView`
struct NavigationViewModifier: ViewModifier{
    func body(content: Content) -> some View {
        NavigationView{
            content
                .modifier(ToolbarViewModifier())
        }
    }
}
///`toolbar` that can be used by the root view of the navigation
///and the children of the navigation
struct ToolbarViewModifier: ViewModifier{
    let title: String = "Company Name"
    func body(content: Content) -> some View {
        content
            .toolbar {
                ToolbarItem(placement: .principal) {
                    VStack{
                        Image(systemName: "sparkles")
                        Text(title)
                    }
                }
            }
    }
}

然后视图会像这样使用它。
import SwiftUI

struct CustomTabView: View {
    var body: some View {
        TabView{
            ForEach(0..<4){ n in
                CustomChildView(title: n.description)
                    //Each tab gets a `NavigationView` and the shared toolbar
                    .modifier(NavigationViewModifier())
                    .tabItem {
                        Text(n.description)
                    }
            }
        }
    }
}
struct CustomChildView: View {
    let title: String
    @State private var showConfirmation: Bool = false
    var body: some View {
        VStack{
            Text(title)
            
            NavigationLink {
                CustomChildView(title: "\(title) :: \(UUID().uuidString)")
            } label: {
                Text("open child")
            }
            Button("show confirmation") {
                showConfirmation.toggle()
            }
            .confirmationDialog("Confirm?", isPresented: $showConfirmation) {
                Button("Yes") {
                    print("yes")
                }
                Button("No", role: .destructive) {
                    print("no")
                }
            }
        }
        //Each child uses the shared toolbar
        .modifier(ToolbarViewModifier())
        
    }
}

我坚持使用NavigationView,因为这是您代码中的内容,但是如果我们考虑新的NavigationStack,这两个修饰符的可能性会成倍增加。

您可以包含自定义返回按钮,仅在路径不为空时才出现,从任何位置返回到根目录等。

苹果公司说:

选项卡栏使用标签项在同一视图中导航到互斥面板的内容

确保当人们在应用程序中导航到不同区域时,选项卡栏可见

https://developer.apple.com/design/human-interface-guidelines/components/navigation-and-search/tab-bars/

NavigationViewNavigationStack置于顶部违反了这些指南,因此是无尽错误的来源,特别是当考虑到iPadOS时。


-1

简单的解决方案是使用navigationDestination

struct testApp: App {
    
    @State var goToSubPage = false
    
    var body: some Scene {
        WindowGroup {
            NavigationStack {
                TabView() {
                    Form {
                        VStack {
                            Image(systemName: "clock")
                            Text("Sub Page")
                        }
                        .onTapGesture {
                            goToSubPage = true
                        }
                        // This is where more menu options would be
                    }
                    .navigationDestination(isPresented: $goToSubPage, destination: {
                        SubPage()
                    })
                    .tag(1)
                    .tabItem {
                        Image(systemName: "square.grid.2x2")
                        Text("Tab 1")
                    }
                    // This is where more tab pages would be
                }
            }
        }
    }
}

我测试了一下,它不会再自己弹出来了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接