0

In my app, I have a main list view with NavigationLinks to detail views. There is an onURLOpen modifier on the main view that will change a state selection variable to navigate to the appropriate detail view (using tagged NavigationLinks that are bound to the selection variable).

This works perfectly well as long as the app is on the main list view (the correct detail view will be pushed). However, if the app is already on a different detail view, the app will pop the old detail view, push the correct detail view, but then pop the correct view and end up back on the main view.

GIF of the issue:

GIF of the issue

This simplified code illustrates the problem:

import SwiftUI

struct ListView: View {
    @State private var selection: Int?
    
    var body: some View {
        NavigationView {
            List {
                NavigationLink(
                    destination: DetailView(selection: $selection),
                    tag: 1,
                    selection: $selection) {
                    Text("Option 1")
                }
                NavigationLink(
                    destination: DetailView(selection: $selection),
                    tag: 2,
                    selection: $selection) {
                    Text("Option 2")
                }
            }
            .navigationTitle("Options")
        }
    }
}

struct DetailView: View {
    @Binding var selection: Int?
    
    var body: some View {
        ZStack {
            switch selection {
            case 1:
                Button {
                    selection = 2
                } label: {
                    Text("Go to Option 2")
                }
            case 2:
                Button {
                    selection = 1
                } label: {
                    Text("Go to Option 1")
                }
            default:
                Text("No option selected")
            }
        }
        .navigationTitle("Option \(selection ?? 0)")
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ListView()
    }
}

Is this expected behavior for NavigationLink? Is there a better way of doing this? I'd be grateful for any pointers.

So far, I've tried adding extra invisible NavigationLinks, NavigationLink with isActive: Binding<Bool>, the isDetailLink modifier, and an ObservableObject instead of a Binding.

Tested in Xcode 12.5 / iOS 14.5.

Anton Krug
  • 1,555
  • 2
  • 19
  • 32
coughski
  • 1
  • 2

1 Answers1

0

Rather than using a binding, I would use an ObservableObject. There seems to be an issue with NavigationLink that will cause the views to bounce like that. I answered a similar question here, but I couldn't remember why the ObservableObject worked. I still haven't found what I based my answer on, but it does seem to correct the problem.

Yrb
  • 8,103
  • 2
  • 14
  • 44
  • Thanks for the suggestion! However, that doesn't work in this case, I'm still seeing the same behavior, even with an `ObservableObject`. – coughski May 27 '21 at 01:51
  • I am hoping it is resolved in the next iteration. Not holding my breath. It is more alchemy than coding to fix. Good luck. – Yrb May 27 '21 at 13:36
  • It looks like this may have been a new implementation of an old bug introduced in 14.5 see [https://developer.apple.com/forums/thread/677333](SwiftUI NavigationLink pops out by itself) and [https://forums.swift.org/t/14-5-beta3-navigationlink-unexpected-pop/45279](https://forums.swift.org/t/14-5-beta3-navigationlink-unexpected-pop/45279). There are a couple of workarounds being discussed as well as the reminder to me that adding a `.navigationViewStyle(StackNavigationViewStyle())` can often help. – Yrb May 27 '21 at 15:20