如何为 SwiftUI 动态构建视图并呈现它?

How can I dynamically build a View for SwiftUI and present it?

我已经包含了存根代码示例。我不确定如何让这个演示文稿发挥作用。我的期望是,当评估 sheet 表示闭包时,aDependency 应该是非零的。但是,正在发生的事情是 aDependency 被视为 nil,而 TheNextView 永远不会出现在屏幕上。

如何建模才能显示 TheNextView?我在这里错过了什么?

struct ADependency {}

struct AModel {
    func buildDependencyForNextExperience() -> ADependency? {
        return ADependency()
    }
}

struct ATestView_PresentationOccursButNextViewNotShown: View {
    @State private var aDependency: ADependency?
    @State private var isPresenting = false
    @State private var wantsPresent = false {
        didSet {
            aDependency = model.buildDependencyForNextExperience()
            isPresenting = true
        }
    }
    private let model = AModel()
    
    var body: some View {
        Text("Tap to present")
            .onTapGesture {
                wantsPresent = true
            }
            .sheet(isPresented: $isPresenting, content: {
                if let dependency = aDependency {
                    // Never executed
                    TheNextView(aDependency: dependency)
                }
            })
    }
}

struct TheNextView: View {
    let aDependency: ADependency
    
    init(aDependency: ADependency) {
        self.aDependency = aDependency
    }
    
    var body: some View {
        Text("Next Screen")
    }
}

这是 iOS14 中的一个常见问题。sheet(isPresented:) 在第一次渲染时得到评估,然后没有正确更新。

要解决这个问题,您可以使用 sheet(item:)。唯一的问题是您的商品必须符合 Identifiable.

您的代码的以下版本有效:

struct ADependency : Identifiable {
    var id = UUID()
}

struct AModel {
    func buildDependencyForNextExperience() -> ADependency? {
        return ADependency()
    }
}

struct ContentView: View {
    @State private var aDependency: ADependency?
    private let model = AModel()
    
    var body: some View {
        Text("Tap to present")
            .onTapGesture {
                aDependency = model.buildDependencyForNextExperience()
            }
            .sheet(item: $aDependency, content: { (item) in
                TheNextView(aDependency: item)
            })
    }
}