Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI ToolbarItem doesn't present a View from a NavigationLink

Tags:

swiftui

I don't know if this is a bug or I am doing something wrong here. I've added a new button on the Navigation bar that would present a new view.

struct MyView: View {
  
  @ObservedObject var viewModel = MyViewModel()
  
  var body: some View {
    List(viewModel.data, id: \.name) { data in
      NavigationLink(destination: MyDetailView(data: data.name)) {
        Text(data.name)
      }
    }
    .listStyle(InsetGroupedListStyle())
    .edgesIgnoringSafeArea(.all)
    .toolbar {
      ToolbarItem(placement: .navigationBarTrailing) {  
        NavigationLink(destination: MyDetailView()) {
          Text("New Element")
        }
      }
    }
  }
}

This is being tested on the newest iOS 14 beta (beta 6) and Xcode 12 (beta 6). As far as I know a Navigation Link presents fine the new view when on a List but in the toolbar as shown that's not the case. The button on the toolbar it's visible and active but doesn't trigger showing the new view.

like image 245
javierdemartin Avatar asked Aug 26 '20 16:08

javierdemartin


People also ask

What are the use cases for navigationlink in SwiftUI?

In this article, we saw the following use cases for NavigationLink in SwiftUI: Programmatic dismissing of views. Removing default navigation back button. Using NavigationLink with other view types. That’s it for this one.

Can a navigationview have a navigationlink inside it?

In doing so, we ensure that the detail views aren’t presented as a separate “detail” component of the containing NavigationView. By default, a ContextMenu, Toolbar, or other types of view presentation cannot contain a NavigationLink inside it.

How to make navigationlink work in a toolbar?

As you might know, NavigationLink doesn't work well when placed in a toolbar. What is suggested here - is to place a Button into a toolbar and use a hidden NavigationLink somewhere in the code. The button tells the link to open the detail view and the link does the action. Here is your code adjusted with this suggestion:

How do I get back to the root view in SwiftUI?

The goal is simple: For a navigation stack like ContentView -> View1 -> View2 -> View3, we need to get back to ContentView from View3. As explained in this Stack Overflow post, to pop to the root SwiftUI view, we need to set an isDetailLink (false) modifier on each NavigationLink.


2 Answers

I found using an HStack with an empty text as the first element also works, it lets the navigationLink act correctly.

        .toolbar {
        ToolbarItem(placement: .navigationBarLeading) {
            HStack {
                Text("")
                NavigationLink(destination: SettingsView()) {
                    Image(systemName: "gear")
                        .font(.title)
                }
            }
        }
like image 93
FBronner Avatar answered Nov 07 '22 09:11

FBronner


NavigationLink should be inside NavigationView. Toolbar is not in NavigationView, put buttons in it.

So assuming you have somewhere in parent

NavigationView {
   MyView()
}

here is a solution:

struct MyView: View {
  
  @ObservedObject var viewModel = MyViewModel()
  @State private var showNew = false

  var body: some View {
    List(viewModel.data, id: \.name) { data in
      NavigationLink(destination: MyDetailView(data: data.name)) {
        Text(data.name)
      }
    }
    .listStyle(InsetGroupedListStyle())
    .background(
        NavigationLink(destination: MyDetailView(), isActive: $showNew) {
          EmptyView()
        }
    )
    .edgesIgnoringSafeArea(.all)
    .toolbar {
      ToolbarItem(placement: .navigationBarTrailing) {  
        Button("New Element") {
            self.showNew = true
        }
      }
    }
  }
}

backup

like image 42
Asperi Avatar answered Nov 07 '22 07:11

Asperi