【问题标题】:Dismiss sheet SwiftUI关闭工作表 SwiftUI
【发布时间】:2019-07-27 14:55:19
【问题描述】:

我正在尝试为我的模式表实现一个关闭按钮,如下所示:

struct TestView: View {
    @Environment(\.isPresented) var present
    var body: some View {
        Button("return") {
            self.present?.value = false
        }
    }
}

struct DataTest : View {
    @State var showModal: Bool = false

    var modal: some View {
        TestView()
    }
    var body: some View {
        Button("Present") {
            self.showModal = true
        }.sheet(isPresented: $showModal) {
            self.modal
        }
    }
}

但是点击返回按钮时什么都不做。当模态显示时,控制台中会出现以下内容:

[WindowServer] display_timer_callback:意外状态(现在:5fbd2efe5da4

如果你强制解开present,你会发现它是nil

如何以编程方式关闭.sheet

【问题讨论】:

  • 从 iOS 15 开始,我们可以使用 DismissAction - 请参阅 this answer

标签: swiftui


【解决方案1】:

使用@Environment 中的presentationMode

测试版 6

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

    var body: some View {
        VStack {
            Text("Ohay!")
            Button("Close") {
                self.presentationMode.wrappedValue.dismiss()
            }
        }
    }
}

【讨论】:

  • 不工作。您能否解释更多或添加更多代码。
  • 关闭工作表的两种方法(这个方法和注入 isShowing 绑定)的一个令人讨厌的事情是,当您点击关闭时,工作表方法的 onDismiss 闭包不会触发按钮。但是如果用户通过向下滑动来关闭模式,它将触发。可能会向 Apple 提出这个问题。
  • 不幸的是,这似乎不适用于 macOS 导航视图,其中列表和视图同时显示。有什么已知的方法吗?
  • 由于presentationMode 是一个绑定路径,您实际上可以在@Environment 中嵌套一个@Binding 以摆脱.wrappedValue 部分。
  • 在工作表中使用 NavigationView 时,此选项不起作用。 dismiss() 弹出导航视图。它不会关闭工作表。
【解决方案2】:

对我来说,beta 4 打破了这种方法——使用环境变量isPresented——使用关闭按钮。这就是我现在所做的:

struct ContentView: View {
    @State var showingModal = false

    var body: some View {
        Button(action: {
           self.showingModal.toggle()
        }) {
           Text("Show Modal")
        }
        .sheet(
            isPresented: $showingModal,
            content: { ModalPopup(showingModal: self.$showingModal) }
        )
    }
}

在你的模态视图中:

struct ModalPopup : View {
    @Binding var showingModal:Bool

    var body: some View {
        Button(action: {
            self.showingModal = false
        }) {
            Text("Dismiss").frame(height: 60)
        }
    }
}

【讨论】:

  • 是的,这是目前唯一的方法。 isPresented 仅在您将其与已弃用的 PresentationLink 一起使用时才有效,但前提是它不用作导航栏项目。
  • @Marc_T.,我之前在这里提到过一次,回复和我一样沮丧——为什么要改变? (我显然不是 Swift Evolution 的一部分 - 希望我说得对。) Beta 2 == PresentationButton。测试版 3 == PresentationLink。 Beta 4 == 嗯,对不起,这一切都已被弃用并且“你搞砸了”?您是否有关于为什么会发生这种事情的链接?相信我,我了解测试版。理解我们也在谈论版本一,如Swift 1.0。也许我对这种事情背后的政治有点天真——但我很聪明。并且很想知道发生了什么。
【解决方案3】:

iOS 15

从 iOS 15 开始,我们可以使用 DismissAction,它可以作为 @Environment(\.dismiss) 访问。

不再需要使用presentationMode.wrappedValue.dismiss()

struct SheetView: View {
    @Environment(\.dismiss) var dismiss

    var body: some View {
        NavigationView {
            Text("Sheet")
                .toolbar {
                    Button("Done") {
                        dismiss()
                    }
                }
        }
    }
}

【讨论】:

    【解决方案4】:

    Apple 推荐(在WWDC 2020 Data Essentials in SwiftUI 中)为此使用@State@Binding。他们还将 isEditorPresented 布尔值和工作表的数据放在使用 @State 声明的同一 EditorConfig 结构中,以便可以对其进行变异,如下所示:

    import SwiftUI
    
    struct Item: Identifiable {
        let id = UUID()
        let title: String
    }
    
    struct EditorConfig {
        var isEditorPresented = false
        var title = ""
        var needsSave = false
        
        mutating func present() {
            isEditorPresented = true
            title = ""
            needsSave = false
        }
        
        mutating func dismiss(save: Bool = false) {
            isEditorPresented = false
            needsSave = save
        }
    }
    
    struct ContentView: View {
        
        @State var items = [Item]()
        @State private var editorConfig = EditorConfig()
        
        var body: some View {
            NavigationView {
                Form {
                    ForEach(items) { item in
                        Text(item.title)
                    }
                }
                .navigationTitle("Items")
                .toolbar {
                    ToolbarItem(placement: .primaryAction) {
                        Button(action: presentEditor) {
                            Label("Add Item", systemImage: "plus")
                        }
                    }
                }
                .sheet(isPresented: $editorConfig.isEditorPresented, onDismiss: {
                    if(editorConfig.needsSave) {
                        items.append(Item(title: editorConfig.title))
                    }
                }) {
                    EditorView(editorConfig: $editorConfig)
                }
            }
        }
        
        func presentEditor() {
            editorConfig.present()
        }
    }
    
    struct EditorView: View {
        @Binding var editorConfig: EditorConfig
        var body: some View {
            NavigationView {
                Form {
                    TextField("Title", text:$editorConfig.title)
                }
                .toolbar {
                    ToolbarItem(placement: .confirmationAction) {
                        Button(action: save) {
                            Text("Save")
                        }
                        .disabled(editorConfig.title.count == 0)
                    }
                    ToolbarItem(placement: .cancellationAction) {
                        Button(action: dismiss) {
                            Text("Dismiss")
                        }
                    }
                }
            }
        }
        
        func save() {
            editorConfig.dismiss(save: true)
        }
        
        func dismiss() {
            editorConfig.dismiss()
        }
    }
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView(items: [Item(title: "Banana"), Item(title: "Orange")])
        }
    }
    

    【讨论】:

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