【问题标题】:SwiftUI sheet not dismissing when isPresented value changes from a closure当 isPresented 值从闭包更改时,SwiftUI 工作表不会关闭
【发布时间】:2020-11-09 05:54:20
【问题描述】:

当用户单击一个按钮时,我有一个工作表视图,如下面的父视图所示:

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)
            }
        }
    }
}

在工作表视图中,当用户单击另一个按钮时,具有完成处理程序的商店会执行一个操作。完成处理程序返回一个对象值,如果该值存在,则应关闭 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() 函数中,一旦商店返回值并且将showingSheetView 设置为false,工作表视图不会按预期关闭。我也尝试过使用 PresentationMode 来关闭工作表,但这似乎也不起作用。

【问题讨论】:

    标签: ios swift xcode swiftui ios13


    【解决方案1】:

    我发现了我的问题,由于我的整体应用程序包装视图中的条件,工作表没有被关闭,我有一个 if 语句会在应用程序启动时显示加载视图,但是,在我的 DataStore 中,我设置它正在获取它执行的每个函数调用上的变量。当该值更改时,我的工作表视图后面的视图堆栈将重新呈现 LoadingView,然后一旦获取变量再次更改,我的 TabView 将重新呈现。这使得工作表视图不可关闭。这是我的 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)
        }
    }
    

    【讨论】:

    • 我现在有基本相同的问题;我的工作表是从登录视图调用的注册视图。注册后,我的注册表的底层视图从登录视图更改为“已登录”视图,这使得我的表不可关闭 - 我认为由于我的登录视图的“正文”(在其上调用表),不再更新,因此不会关闭工作表。很烦人的是工作表不能自行关闭。
    【解决方案2】:

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

    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 !!
        }
    }
    

    【讨论】:

    • 我尝试了您的建议,但不幸的是,该视图仍然没有消除。对象肯定有一个值,showingSheetView 变量的值确实设置为 false,但是工作表仍然没有关闭。
    【解决方案3】:

    想看一些对我有用的 hacky 吗?免责声明:可能不适合你,我不一定推荐它。但也许它会帮助处于紧要关头的人。

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

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

    将此添加到您的body,并保持您的工作表原样:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-04
      • 2021-05-04
      • 2020-06-04
      • 1970-01-01
      • 1970-01-01
      • 2022-01-07
      相关资源
      最近更新 更多