简体   繁体   中英

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

I've included stubbed code samples. I'm not sure how to get this presentation to work. My expectation is that when the sheet presentation closure is evaluated, aDependency should be non-nil. However, what is happening is that aDependency is being treated as nil, and TheNextView never gets put on screen.

How can I model this such that TheNextView is shown? What am I missing here?

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")
    }
}

This is a common problem in iOS 14. The sheet(isPresented:) gets evaluated on first render and then does not correctly update.

To get around this, you can use sheet(item:) . The only catch is your item has to conform to Identifiable .

The following version of your code works:

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)
            })
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM