Programmatic push with NavigationLink via isActive during onAppear is automatically dismissed

I want to init a navigation stack in SwiftUI. Thus I want to push a second view immediately after a first view appears. Approach: Using a @State var, which is set to true in onAppear, and thus activates a NavigationLink in first view.

However, the approach is not working. The push is done and then the second view is immediately dismissed. The expected behaviour is that the second screen stays on screen.

This is a simplified demo:

Code Block
struct SecondView: View {
var body: some View {
Text("Second")
.navigationTitle("Second")
.onAppear(perform: {
print("Second: onAppear")
})
}
}
struct FirstView: View {
@State var linkActive = false
var body: some View {
NavigationLink(destination: SecondView(), isActive: $linkActive) {
Text("Goto second")
}
.navigationTitle("First")
.onAppear(perform: {
print("First: onAppear")
linkActive = true
})
.onChange(of: linkActive) { value in
print("First: linkActive changed to: \(linkActive)")
}
}
}
struct SwiftUIView: View {
var body: some View {
NavigationView {
NavigationLink(destination: FirstView()) {
Text("Goto first")
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}


Log output:

Code Block
First: onAppear
First: linkActive changed to: true
Second: onAppear
First: linkActive changed to: false


Trying to figure out if this is a SwiftUI bug, or something I’m doing wrong. May someone help?
  • I'm stuck on this right now, did you find a solution?

Add a Comment

Replies

I have confirmed the behavior both in simulator and an actual device (iOS 14.3).

to figure out if this is a SwiftUI bug

I'm not sure if this is a bug or not, but assuming not a bug, we have no ways to control navigation links programmatically.
You should better send a feedback on this issue soon.
FB8954491
Add a Comment

If anyone comes across this in the future, I solved this problem with the following:

struct View1: View{

@State var KeepView2: Bool = false 

  var body: some View{
     if self.KeepView2{
         NavigationLink(destination: View2(keepViewOpen: self.$keepView2), isActive: self.$keepView2){
             Text("Navigate")
         }
     }
  }
}

struct View2: View{

@Binding keepViewOpen: Bool

var body: some View{
VStack{
      Text("Hello World")
}.onAppear{

self.keepViewOpen = true 
       }
   }
}
  • How would this work if View1 looked like this:

    struct View1: View{

    var body: some View{

    LazyVGrid(columns: gridLayout, spacing: 10) { ForEach(Array(person.item! as! Set<Item>).sorted { $0.date! > $1.date! }, id: \.self) { (item: Item) in NavigationLink(destination: View2(){ Text("Navigate") } } }

    } }

    I can't get it to compile properly if the if self.KeepView2 is right before the NavigationLink. And if I put it before the LazyVGrid, it won't display the contents of the ForEach Array. Thanks!

  • This worked for sometime for me but it doesn't anymore. Did you find another solution to this?

  • This actually worked for me just now for iOS 14.8 on iPad. Thanks!

Add a Comment

This worked for sometime for me but it doesn't anymore. Did you find another solution to this?