Luke
Luke

Reputation: 35

Picker selection within navigation link causes strange behaviour

I have a picker embedded in a form on a screen within a navigation view stack. I've re-created a simplistic version.

struct ContentView: View {
    
    @State var showSecondView: Bool = false
    
    var body: some View {
        NavigationView {
            VStack {
                Button("SecondView", action: {
                    self.showSecondView = true
                })
                NavigationLink(destination: SecondContentView(), isActive: $showSecondView) {
                    EmptyView()
                }
            }
        }
        
    }
}

struct SecondContentView: View {
    
    @State var showThirdView: Bool = false
    
    var body: some View {
            VStack {
                Button("ThirdView", action: {
                    self.showThirdView = true
                })
                NavigationLink(destination: ThirdContentView(showThirdView: $showThirdView), isActive: $showThirdView) {
                    EmptyView()
                }
            }
    }
}

struct ThirdContentView: View {
    
    @Binding var showThirdView: Bool
    @State var pickerSelection: String = ""
    let pickerObjects = ["A", "B", "C"]
    
    var body: some View {
            VStack {
                Form {
                    Picker(selection: $pickerSelection, label: Text("Abort Reason")
                    ) {
                        ForEach(0 ..< pickerObjects.count) { i in
                            Text("\(self.pickerObjects[i])").tag(self.pickerObjects[i])
                        }
                    }
                }
                Button("Done", action: {
                    self.showThirdView.toggle()
                })
            }
    }
}

In the example above when I set a value and press done it navigates back to the third screen (with the picker) but without a value selected. In my full app pressing done dismisses the third screen but then when I press back on the second screen it briefly shows the third screen for a second before dismissing it.

If I present the third view outside of a navigation link (if showThirdView == true) then no navigation errors. The setting of a value in the picker seems to add another instance of the third view to the NavigationView stack rather than going back. I like the navigation link style as the back button is consistent for the user. Is there any way to get the picker to work within a navigation link?

Upvotes: 1

Views: 365

Answers (1)

Asperi
Asperi

Reputation: 257711

Here is fixed parts that works - replaced Binding, which becomes lost, with presentation mode. Tested with Xcode 12 / iOS 14.

struct SecondContentView: View {
    @State var showThirdView: Bool = false

    var body: some View {
            VStack {
                Button("ThirdView", action: {
                    self.showThirdView = true
                })
                NavigationLink(destination: ThirdContentView(), isActive: $showThirdView) {
                    EmptyView()
                }
            }
    }
}

struct ThirdContentView: View {
    @Environment(\.presentationMode) var mode

    @State var pickerSelection: String = ""
    let pickerObjects = ["A", "B", "C"]

    var body: some View {
            VStack {
                Form {
                    Picker(selection: $pickerSelection, label: Text("Abort Reason")
                    ) {
                        ForEach(0 ..< pickerObjects.count) { i in
                            Text("\(self.pickerObjects[i])").tag(self.pickerObjects[i])
                        }
                    }
                }
                Button("Done", action: {
                    self.mode.wrappedValue.dismiss()
                })
            }
    }
}

Upvotes: 1

Related Questions