由于SwiftUI是声明性的,因此没有dismiss
方法。
如何为DetailView
添加一个关闭/关闭按钮?
struct DetailView: View {
var body: some View {
Text("Detail")
}
}
struct ContentView : View {
var body: some View {
PresentationButton(Text("Click to show"), destination: DetailView())
}
}
答案 0 :(得分:17)
消除模态的另一种方法是使用isPresented环境变量,即:
绑定到一个布尔值,该值指示此实例是否为 当前呈现的层次结构的一部分。
您需要做的就是在模式视图中将此变量的值设置为false
:
struct DetailView : View {
@Environment(\.isPresented) var isPresented: Binding<Bool>?
var body: some View {
Group {
Text("Detail view")
Button(action: {
self.isPresented?.value = false
}) {
Text("Dismiss")
}
}
}
}
struct ContentView : View {
var body: some View {
// PresentationButton(Text("Show modal"), destination: DetailView())
// In Xcode 11 beta 3, 'PresentationButton' is deprecated and renamed to 'PresentationLink'
PresentationLink(destination: DetailView()) {
Text("Show modal")
}
}
}
答案 1 :(得分:12)
这是一种消除显示视图的方法。
struct DetailView: View {
@Binding
var dismissFlag: Bool
var body: some View {
Group {
Text("Detail")
Button(action: {
self.dismissFlag.toggle()
}) {
Text("Dismiss")
}
}
}
}
struct ContentView : View {
@State var dismissFlag = false
var body: some View {
Button(action: {
self.dismissFlag.toggle()
})
{ Text("Show") }
.presentation(!dismissFlag ? nil :
Modal(DetailView(dismissFlag: $dismissFlag)) {
print("dismissed")
})
}
}
答案 2 :(得分:8)
对于Xcode 11 Beta 7(这是在Xcode的版本11M392r上),似乎有些不同。
@Environment(\.presentationMode) var presentation
Button(action: { self.presentation.wrappedValue.dismiss() }) { Text("Dismiss") }
答案 3 :(得分:6)
您可以实现这一点。
$ cat file
this/that/maybe/more/and/more
or/even/this/could/be/it/and/maybe/more
short/more
答案 4 :(得分:6)
现在在Beta 5中,有一种非常干净的方法可以做到这一点。
import SwiftUI
struct ModalView : View {
// In Xcode 11 beta 5, 'isPresented' is deprecated use 'presentationMode' instead
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var body: some View {
Group {
Text("Modal view")
Button(action: { self.presentationMode.wrappedValue.dismiss() }) { Text("Dismiss") }
}
}
}
struct ContentView : View {
@State var showModal: Bool = false
var body: some View {
Group {
Button(action: { self.showModal = true }) { Text("Show modal via .sheet modifier") }
.sheet(isPresented: $showModal, onDismiss: { print("In DetailView onDismiss.") }) { ModalView() }
}
}
}
答案 5 :(得分:6)
在xcode beta5中,另一种方法是在启动模式的视图中使用@State,并在模式视图中添加绑定以控制模式的可见性。这不需要您进入@EnvironmentpresentationMode变量。
struct MyView : View {
@State var modalIsPresented = false
var body: some View {
Button(action: {self.modalIsPresented = true}) {
Text("Launch modal view")
}
.sheet(isPresented: $modalIsPresented, content: {
MyModalView(isPresented: self.$modalIsPresented)
})
}
}
struct MyModalView : View {
@Binding var isPresented: Bool
var body: some View {
Button(action: {self.isPresented = false}) {
Text("Close modal view")
}
}
}
答案 6 :(得分:3)
我们现在可以使用 presentationMode
代替 DismissAction
。
以下是来自 documentation 的示例:
struct SheetView: View {
@Environment(\.dismiss) var dismiss
var body: some View {
NavigationView {
SheetContents()
.toolbar {
Button("Done") {
dismiss()
}
}
}
}
}
答案 7 :(得分:2)
由于PresentationButton
易于使用,但是隐藏状态到SwiftUI
的可预测性,我已经使用可访问的Binding
实现了它。
public struct BindedPresentationButton<Label, Destination>: View where Label: View, Destination: View {
/// The state of the modal presentation, either `visibile` or `off`.
private var showModal: Binding<Bool>
/// A `View` to use as the label of the button.
public var label: Label
/// A `View` to present.
public var destination: Destination
/// A closure to be invoked when the button is tapped.
public var onTrigger: (() -> Void)?
public init(
showModal: Binding<Bool>,
label: Label,
destination: Destination,
onTrigger: (() -> Void)? = nil
) {
self.showModal = showModal
self.label = label
self.destination = destination
self.onTrigger = onTrigger
}
public var body: some View {
Button(action: toggleModal) {
label
}
.presentation(
!showModal.value ? nil :
Modal(
destination, onDismiss: {
self.toggleModal()
}
)
)
}
private func toggleModal() {
showModal.value.toggle()
onTrigger?()
}
}
这是它的用法:
struct DetailView: View {
@Binding var showModal: Bool
var body: some View {
Group {
Text("Detail")
Button(action: {
self.showModal = false
}) {
Text("Dismiss")
}
}
}
}
struct ContentView: View {
@State var showModal = false
var body: some View {
BindedPresentationButton(
showModal: $showModal,
label: Text("Show"),
destination: DetailView(showModal: $showModal)
) {
print("dismissed")
}
}
}
答案 8 :(得分:2)
在Xcode 11.0 beta 7中,该值现已包装,以下功能对我有用:
func dismiss() {
self.presentationMode.wrappedValue.dismiss()
}
答案 9 :(得分:1)
在您开始在List
或Form
视图中使用它们之前,SwiftUI中的模式视图似乎很简单。我创建了一个小型库,该库包装了所有边缘情况,并使模态视图的使用与NavigationView
-NavigationLink
对相同。
该库在以下位置开放源代码:https://github.com/diniska/modal-view。您可以使用Swift Package Manager将其包含在项目中,也可以仅复制库中包含的单个文件。
您的代码的解决方案是:
struct DetailView: View {
var dismiss: () -> ()
var body: some View {
Text("Detail")
Button(action: dismiss) {
Text("Click to dismiss")
}
}
}
struct ContentView : View {
var body: some View {
ModalPresenter {
ModalLink(destination: DetailView.init(dismiss:)) {
Text("Click to show")
}
}
}
}
此外,还有一篇文章提供了完整的描述和示例:How to present modal view in SwiftUI
答案 10 :(得分:1)
Navigation
中自动弹出,在Modal
中自动关闭只需从目标视图中的环境中获取presentationMode
,并从其中获取dismiss
的{{1}}:
wrappedValue
答案 11 :(得分:1)
Swift 5.5 和 SwiftUI 3 中的新功能:
@Environment(\.dismiss) var dismiss
然后在函数或正文代码中的某处,只需调用:
self.dismiss()
答案 12 :(得分:0)
在PresentationMode上使用环境变量。 该GitHub链接可能会帮助您解决问题https://github.com/MannaICT13/Sheet-in-SwiftUI
这是简单的解决方案:
struct ContentView2 : View {
@Environment (\.presentationMode) var presentationMode
var body : some View {
VStack {
Text("This is ContentView2")
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}, label: {
Text("Back")
})
}
}
}
struct ContentView: View {
@State var isShowingSheet : Bool = false
var body: some View {
Button(action: {
self.isShowingSheet.toggle()
}, label: {
Text("Click Here")
}).sheet(isPresented: $isShowingSheet, content: {
ContentView2()
})
}
}
答案 13 :(得分:0)
执行此操作的一种方法可能是声明您自己的修饰符以用于模式表示和解雇。
extension View {
func showModal<T>(_ binding: Binding<Bool>, _ view: @escaping () -> T) -> some View where T: View {
let windowHeightOffset = (UIApplication.shared.windows.first?.frame.height ?? 600) * -1
return ZStack {
self
view().frame(maxWidth: .infinity, maxHeight: .infinity).edgesIgnoringSafeArea(.all).offset(x: 0, y: binding.wrappedValue ? 0 : windowHeightOffset)
}
}
}
然后,您可以在想要告知如何显示视图和关闭该视图的任何视图上使用修饰符。就像弹出框或工作表修改器一样。
struct ContentView: View {
@State var showModal = false
var body: some View {
Text("Show").foregroundColor(.blue).onTapGesture {
withAnimation(.easeIn(duration: 0.75)) {
self.showModal = true
}
}.showModal($showModal, {
Text("Dismiss").foregroundColor(.blue).onTapGesture {
withAnimation(.easeIn(duration: 0.75)) {
self.showModal = false
}
}
})
}
}
该演示文稿从顶部开始全屏显示,如果您希望它来自侧面,请将修改器内的过渡更改为前导或尾随。其他转换也可以使用,例如不透明度或缩放。
答案 14 :(得分:0)
(示例代码不适用于swift 1,但您仍可以在没有@main
块的情况下尝试使用它)
使用表格的完整应用示例:
@main
struct TestAppApp: App {
var body: some Scene {
WindowGroup {
SheetLink(text: "click me!", content: ChildView() )
.padding(.all, 100)
}
}
}
struct ChildView: View {
var body: some View {
Text("this is subView!")
}
}
并且子视图大于主视图时:
以及此后的代码:
struct SheetLink<Content> : View where Content: View {
@State var text: String
@State var displaySheet = false
@State var content: Content
var body: some View {
HStack {
Button(text, action: { self.displaySheet = true } ).buttonStyle(PlainButtonStyle()).foregroundColor(.blue)
}
.sheet(isPresented: $displaySheet) {
SheetTemplateView(isPresented: self.$displaySheet, content: content)
}
}
}
struct SheetTemplateView<Content> : View where Content: View {
@Binding var isPresented: Bool
@State var content: Content
var body: some View {
VStack{
HStack{
Button("Back!", action: { isPresented.toggle() } ).buttonStyle(PlainButtonStyle()).foregroundColor(.blue)
Spacer()
}
Spacer()
content
Spacer()
}
.padding()
}
}
答案 15 :(得分:0)
您可以使用演示模式关闭。 声明
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
然后在需要时将其关闭
self.presentationMode.wrappedValue.dismiss()