Toolbar is deleting my back Button in the NavigationView

Viewed 993

I have a Detail view of a list where I navigate to from my main view:

NavigationView {
    ...
    NavigationLink(destination: DetailView()) {
        Text(entity.name ?? "Unknown")
    }
    ...
}

Then in my DetailView I can see the back button to my Main view:

struct DetailView: View {
  
    var body: some View {
        Form {
            ...
        }
        .navigationBarTitle("Deatil")
        /*.toolbar {
            ToolbarItem(placement: .primaryAction) {
                
                Button(action: {
                    ...
                }) {
                    Image(systemName: "ellipsis.circle")
                }
                
            }
            
        }*/
    }
}

Its all fine till I use the toolbar. Then I only see the toolbar but not the navigation to the last view. Why? Usually this should work, right?

2 Answers

I solved it! After experimenting further I discovered that by adding the following toolbar item you can prevent the back button from disappearing in a refreshed view more than three views deep in the navigation hierarchy.

ToolbarItem(placement: .navigationBarLeading) {Text("")}

Note: EmptyView() will not work. The bug seems to need an active toolbar item in the leading position to prevent the back button from disappearing when a view is refreshed three or more views deep in a hierarchy.

As I listed before, when not using this new workaround suggested above, there are a few additional caveats to consider in dealing with this bug.

  • navigationBarItems(trailing:) is deprecated
  • using navigationBarItems(trailing:) and toolbar(content:) in the same NavigationView hierarchy (even when in different views) to avoid this bug will cause a number of visual glitches (duplicate back buttons etc.)
  • Using toolbar(content:) that refreshes the view more than three views deep in a navigation hierarchy will remove the ability (both the button and swipe gesture) to navigate back in that hierarchy.
  • for what it's worth, if you specifically indicate the trailing location of a toolbar item and keep that item within the first two views of the view hierarchy, and you avoid any use of default/ primaryAction or leading placement, and any use of a navigationBarItem, you can avoid most of these bugs.
import SwiftUI

struct ToolbarBug: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: DetailViewToolbarBug()) {
                Text("Unknown")
            }
        }
    }
}
struct DetailViewToolbarBug: View {
    var body: some View {
        VStack{
            NavigationLink(destination: DetailViewToolbarBug()) {
                Text("Unknown")
            }
        Form {
            NavigationLink(destination: DetailViewToolbarBug()) {
                Text("Unknown")
            }
            Text("form text")
        }
        }
        .navigationBarTitle("Deatil")
        .toolbar {
            ToolbarItem(placement: .primaryAction) {
                
                Button(action: {
                    
                }) {
                    Image(systemName: "ellipsis.circle")
                }
            }
        }
    }
}
struct ToolbarBug_Previews: PreviewProvider {
    static var previews: some View {
        ToolbarBug()
    }
}
Related