0

I want to invoke another view programmatically. The way I found to do this was with a NavigationLink with a destination and isactive and a closure of EmpytView. This appears to work nicely. When I set the isactive bool to true the destination view is invoked. The problem I have is that the init for the destination is invoked when the parent view is displayed. In fact, if the destination view is never invoked the init is still driven. In my real app some of the initialization data is not available until I take the link but the init is invoked when the previous view displays.

In the sample I have here the init of the second view is invoked before the first appears. init for the second view is invoked again when I hit the button. If I comment out the x = 2 for the button the init for the second view is only invoked once, and that is before I press the button. The init prints hi before I get the layout messages for the first view and, if I change x, hi prints again followed by the 2. If I comment out the change of x then I get hi, the layout messages for view 1, then the 3.

Is there some way I can stop the init before I am ready or do I have to do something like x is 3 if call at start and x is 2 if called at right time?

import SwiftUI

struct ContentView: View {
  @State private var isShowingDetailView = false
  @State var x:Int
  
  init () {
    x = 3
  }
  var body: some View {
    NavigationView {
      VStack {
        NavigationLink(destination: Second(passed: x), isActive: $isShowingDetailView) { EmptyView() }
        
        Button("Tap to show detail") {
          isShowingDetailView = true
          x = 2
        }
      }
      .navigationTitle("Navigation")
    }
  }
}

struct Second: View {
  @State var passed: Int
  
  init (passed: Int) {
    let y = print("hi")
    self.passed = passed
  }
  var body: some View {
    VStack {
      let x = print (passed)
      Text ("passed: \(passed)")
    }
  }
}
Peter
  • 83
  • 8
  • Maybe you want something like this? https://stackoverflow.com/questions/57594159/swiftui-navigationlink-loads-destination-view-immediately-without-clicking – jnpdx Sep 02 '22 at 23:06
  • just an observation, in `Second` you should be using `_passed = State(initialValue: passed)` not `self.passed = passed`. – workingdog support Ukraine Sep 02 '22 at 23:18

1 Answers1

2

A very simple way to avoid calling Second init(...) before pressing the button, is to do:

if isShowingDetailView {
    NavigationLink(destination: Second(passed: x), isActive: $isShowingDetailView) { EmptyView() }
} 
  • I love simple answers. That worked fine. Sometimes it is hard to remember what code can be in a view and what can not. – Peter Sep 03 '22 at 01:44
  • By giving this condition, the navigation animation is not working. It goes to the next page without the default animation – Murtuza Jan 13 '23 at 14:14
  • @Murtuza, you are right, i can see the same problem too. – LiangWang Mar 03 '23 at 13:39