SwiftUI:从子视图中关闭模式

kye*_*kye 2 uiview ios swift swiftui combine

我试图在其预期操作完成后解除模态,但我不知道目前如何在 SwiftUI 中完成此操作。此模式由@State值更改触发。是否可以通过观察各种通知来更改此值?

想要的动作:Root -> Initial Modal -> Presents Children -> Dismiss modal from any child

以下是我尝试过的

错误:转义闭包捕获变异的“self”参数

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()
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

ModalWithChildren 测试动作


Button(action: {
    NotificationCenter.default.post(
        name: .didCompletePageSave, object: nil)}, 
        label: { Text("Close") })
Run Code Online (Sandbox Code Playgroud)

Fab*_*ian 5

您可以接收.onReceive(_:perform)可以在任何视图上调用的消息。它注册一个接收器并将可取消对象保存在视图中,这使得订阅者的生命周期与视图本身一样长。

通过它,您可以启动@State属性更改,因为它从视图主体开始。否则,您将不得不使用ObservableObject可以从任何地方启动更改的 。

一个例子:

struct MyView : View {
    @State private var currentStatusValue = "ok"
    var body: some View {
        Text("Current status: \(currentStatusValue)")
    }
    .onReceive(MyPublisher.currentStatusPublisher) { newStatus in
        self.currentStatusValue = newStatus
    }
}
Run Code Online (Sandbox Code Playgroud)

一个完整的例子

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") }
    }
}
Run Code Online (Sandbox Code Playgroud)