iosswiftswiftuimobile-development

Swift NavigationLink pushed multiple times


The code should be quite self-explanatory: I have a list of items. When clicking the "...", it pops up a sheet. When clicking the button in the sheet it goes to a complete new view.

However, there are two problems with the implementation:

  1. I have to click "back" multiple times in the third view in order to come back to the main view. How do I fix this?
  2. NavigationLink(isActive) is marked as deprecated. What's the best way to replace it?

Here's the code:

struct TestView: View {
  @State private var secondViewPresented = false
  @State private var thirdViewPresented = false
  
  var body: some View {
    ForEach(["1", "2", "3"], id: \.self) { option in
      HStack {
        Text(option)
        Button(action: {
          self.secondViewPresented = true
        }) {
          Image(systemName: "ellipsis")
            .padding()
        }
      }
    }
    .sheet(isPresented: self.$secondViewPresented) {
      secondView()
    }
    .background(
      NavigationLink(
        destination: ThirdView(),
        isActive: self.$thirdViewPresented
      ) {
        EmptyView()
      }
    )
    .onAppear() {
      // self.thirdViewPresented = false - doesn't help
    }
  }
  
  private func secondView() -> some View {
    HStack {
      Button(action: {
        self.secondViewPresented = false
        self.thirdViewPresented = true
      }) {
        HStack {
          Text("Go to 3rd View \(thirdViewPresented)")
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
      }
    }
    .presentationDetents([.fraction(0.1)])
    .padding()
  }
}

struct ThirdView: View {
  var body: some View {
    Text("ThirdView")
  }
}

#Preview {
  NavigationStack {
    TestView()
  }
}

Solution

  • You should use the navigationDestination(isPresented:destination:) modifier, instead of an invisible NavigationLink as the background.

    .navigationDestination(isPresented: $thirdViewPresented) {
        ThirdView()
    }
    

    After that, the third view does not get pushed multiple times.