关闭工作表 SwiftUI
Posted
技术标签:
【中文标题】关闭工作表 SwiftUI【英文标题】:Dismiss sheet 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。
【参考方案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")])
【讨论】:
以上是关于关闭工作表 SwiftUI的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI:.sheet() 在关闭当前工作表时不会使用预期数据转到上一个视图