Since SwiftUI is declarative there is no dismiss
methode.
How can is add a dismiss/close button to the DetailView
?
struct DetailView: View {
var body: some View {
Text("Detail")
}
}
struct ContentView : View {
var body: some View {
PresentationButton(Text("Click to show"), destination: DetailView())
}
}
In Xcode 11.0 beta 5, you can use presentationMode
to dismiss modal:
struct ModalView : View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var body: some View {
Group {
Text("Modal view")
Button(action: {
self.presentationMode.value.dismiss()
}) {
Text("Dismiss")
}
}
}
}
Update: isPresented
seems to be deprecated on beta 5.
Another way to dismiss the modal is using isPresented environment variable, which is:
A binding to a Boolean value that indicates whether this instance is part of a currently-presented hierarchy.
All you need to do is to set this variable's value to false
in your modal view:
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")
}
}
}
Here's a way to dismiss the presented view.
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")
})
}
}
You can implement this.
struct view: View {
@Environment(\.isPresented) private var isPresented
private func dismiss() {
isPresented?.value = false
}
}
There is now a pretty clean way to do this in 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.value.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() }
}
}
}
Since PresentationButton
is easy to use but hiding the state wich is undermining the predictive character of SwiftUI
I have implemented it with an accessible 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?()
}
}
This is how it is used:
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")
}
}
}
In xcode beta5, another way to do this is to use @State in the view that launches the modal, and add a binding in the modal view to control visibility of the modal. This doesn't require you to reach into the @Environment presentationMode variable.
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")
}
}
}
来源:https://stackoverflow.com/questions/56517400/swiftui-dismiss-modal