Reputation: 2246
I'm attempting to dismiss a modal after its intended action is completed, but I have no idea how this can be currently done in SwiftUI. This modal is triggered by a @State
value change. Would it be possible to change this value by observing a notification of sorts?
Desired actions: Root -> Initial Modal -> Presents Children -> Dismiss modal from any child
Below is what I've tried
Error: Escaping closure captures mutating 'self' parameter
struct AContentView: View {
@State var pageSaveInProgress: Bool = false
init(pages: [Page] = []) {
// Observe change to notify of completed action
NotificationCenter.default.publisher(for: .didCompletePageSave).sink { (pageSaveInProgress) in
self.pageSaveInProgress = false
}
}
var body: some View {
VStack {
//ETC
.sheet(isPresented: $pageSaveInProgress) {
ModalWithChildren()
}
}
}
}
ModalWithChildren test action
Button(action: {
NotificationCenter.default.post(
name: .didCompletePageSave, object: nil)},
label: { Text("Close") })
Upvotes: 3
Views: 1396
Reputation: 5348
You can receive messages through .onReceive(_:perform)
which can be called on any view. It registers a sink and saves the cancellable inside the view which makes the subscriber live as long as the view itself does.
Through it you can initiate @State
attribute changes since it starts from the view body. Otherwise you would have to use an ObservableObject
to which change can be initiated from anywhere.
An example:
struct MyView : View {
@State private var currentStatusValue = "ok"
var body: some View {
Text("Current status: \(currentStatusValue)")
}
.onReceive(MyPublisher.currentStatusPublisher) { newStatus in
self.currentStatusValue = newStatus
}
}
import SwiftUI
import Combine
extension Notification.Name {
static var didCompletePageSave: Notification.Name {
return Notification.Name("did complete page save")
}
}
struct OnReceiveView: View {
@State var pageSaveInProgress: Bool = true
var body: some View {
VStack {
Text("Usual")
.onReceive(NotificationCenter.default.publisher(for: .didCompletePageSave)) {_ in
self.pageSaveInProgress = false
}
.sheet(isPresented: $pageSaveInProgress) {
ModalWithChildren()
}
}
}
}
struct ModalWithChildren: View {
@State var presentChildModals: Bool = false
var body: some View {
Button(action: {
NotificationCenter.default.post(
name: .didCompletePageSave,
object: nil
)
}) { Text("Send message") }
}
}
Upvotes: 6