SwiftUI sheet 当 isPresented 值从闭包更改时不解除

SwiftUI sheet not dismissing when isPresented value changes from a closure

我有一个 sheet 视图,当用户单击如下父视图所示的按钮时会显示该视图:

struct ViewWithSheet: View {
    @State var showingSheetView: Bool = false
    @EnvironmetObject var store: DataStore()

    var body: some View {
        NavigationView() {
            ZStack {
               Button(action: { self.showingSheetView = true }) {
                   Text("Show sheet view")
               }
            }
            .navigationBarHidden(true)
            .navigationBarTitle("")
            .sheet(isPresented: $showingSheetView) {
                SheetView(showingSheetView: self.$showingSheetView).environmentObject(self.dataStore)
            }
        }
    }
}

在 sheet 视图中,当用户单击另一个按钮时,具有完成处理程序的商店会执行一个操作。完成处理程序 returns 一个对象值,如果该值存在,应该关闭 SheetView。

struct SheetView: View {

    @Binding var showingSheetView: Bool

    @EnvironmentObject var store: DataStore()

    //@Environment(\.presentationMode) private var presentationMode

    func create() {
        store.createObject() { object, error in 
           if let _ = object {
               self.showingSheetView = false
               // self.presentationMode.wrappedValue.dismiss()
           }
        }
    }

    var body: some View {
        VStack {
            VStack {
                HStack {
                    Button(action: { self.showingSheetView = false }) {
                        Text("Cancel")
                    }
                    
                    Spacer()
                    
                    Spacer()
                    
                    Button(action: { self.create() }) {
                        Text("Add")
                    }
                }
                .padding()
            }
        }
    }
}

但是,在 create() 函数中,一旦存储 returns 值和 showingSheetView 设置为 false,sheet 视图不会按预期关闭。我也尝试过使用 presentationMode 关闭 sheet,但这似乎也不起作用。

尝试在主队列上显式执行此操作

func create() {
    store.createObject() { object, error in 
       if let _ = object {
           DispatchQueue.main.async {
              self.showingSheetView = false
           }
       }
       // think also about feedback on else case as well !!
    }
}

我发现了我的问题,sheet 并没有因为我的整体应用程序包装视图中的条件而被解雇,我有一个 if 语句会在应用程序启动时显示加载视图,但是,在我的DataStore 我在它执行的每个函数调用上设置它的获取变量。当该值更改时,我的 sheet 视图后面的视图堆栈将重新呈现 LoadingView,然后在获取变量再次更改后重新呈现我的 TabView。这使得 sheet 视图不可关闭。这是我的 AppView 的示例:

struct AppView: View {

    @State private var fetchMessage: String = ""

    @EnvironmentObject var store: DataStore()

    func initializeApp() {
        self.fetchMessage = "Getting App Data"
        store.getData() { object, error in 
            if let error = error {
                self.fetchMessage = error.localizedDescription
            }

            self.fetchMessage = ""
        }
    }

    var body: some View {
        Group {
            ZStack {
                //this is where my issue was occurring
                if(!store.fetching) {
                    TabView {
                        Tab1().tabItem {
                            Image(systemName: "tab-1")
                            Text("Tab1")
                        }

                        Tab2().tabItem {
                            Image(systemName: "tab-2")
                            Text("Tab2")
                        }

                        //Tab 3 contained my ViewWithSheet() and SheetView()
                        Tab3().tabItem {
                            Image(systemName: "tab-3")
                            Text("Tab3")
                        }
                    }
                } else {
                    LoadingView(loadingMessage: $fetchMessage)
                }
            }
        }.onAppear(perform: initializeApp)
    }
}

为了解决我的问题,我在 DataStore 中添加了另一个名为 initializing 的变量,我用它来呈现加载屏幕或应用程序中第一个 .onAppear 事件的实际应用程序视图。下面是我更新后的 AppView 的示例:

struct AppView: View {

    @State private var fetchMessage: String = ""

    @EnvironmentObject var store: DataStore()

    func initializeApp() {
        self.fetchMessage = "Getting App Data"
        store.getData() { object, error in 
            if let error = error {
                self.fetchMessage = error.localizedDescription
            }

            self.fetchMessage = ""
            //set the value to false once I'm done getting my app's initial data.
            self.store.initializing = false
        }
    }

    var body: some View {
        Group {
            ZStack {
                //now using initializing instead
                if(!store.initializing) {
                    TabView {
                        Tab1().tabItem {
                            Image(systemName: "tab-1")
                            Text("Tab1")
                        }

                        Tab2().tabItem {
                            Image(systemName: "tab-2")
                            Text("Tab2")
                        }

                        //Tab 3 contained my ViewWithSheet() and SheetView()
                        Tab3().tabItem {
                            Image(systemName: "tab-3")
                            Text("Tab3")
                        }
                    }
                } else {
                    LoadingView(loadingMessage: $fetchMessage)
                }
            }
        }.onAppear(perform: initializeApp)
    }
}

想看看对我有用的骇人听闻的东西吗?免责声明:可能不适合你,我不一定推荐它。但也许它会在紧要关头帮助某人。

如果您添加 NavigationLink 并保留 fullScreenCover,那么全屏封面将能够像您预期的那样自行关闭。

为什么将 NavigationLink 添加到视图时会发生这种情况?我不知道。我的猜测是它在某处创建了一个额外的引用。

将此添加到您的 body,并保持您的 sheet 不变:

NavigationLink(destination: YOURVIEW().environmentObjects(), isActive: $showingSheetView) {}