6

I need a "Plus" ⊕ Button in my NavigationView's List .navigationBarItems (right on the navigation bar), which I'd like to add a row to the list, using a subsequent view in the navigation hierarchy to enter its name etc.

enter image description here

But first, I can't even get the button to navigate correctly! When I tap it in the Preview Canvas, the button's operation seems to work. Yet in an actual app, while it does navigate to my destination View, when I tap that View's "< Back" button, the app crashes with:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Tried to pop to a view controller that doesn't exist.'

Any suggestions how I may fix the following code, please? This task is so common, surely I'm missing something and doing it wrong.

import SwiftUI

struct ListItem: Identifiable {
    var id = UUID()
    var name: String
}

struct ContentView: View {
    var listItems = [
        ListItem(name: "List Item One"),
        ListItem(name: "List Item Two")
    ]

    var body: some View {
        NavigationView {
            List(listItems) { listItem in
                NavigationLink(destination: DetailView(existingItem: listItem)) {
                    Text(listItem.name)
                }
            }
            .navigationBarTitle(Text("Configure List Items"), displayMode: .inline)
            .navigationBarItems(trailing:
                    NavigationLink(destination: DetailView(existingItem: nil)) {
                                        Image(systemName: "plus")
                                            .resizable()
                                            .padding(6)
                                            .frame(width: 24, height: 24)
                                            .background(Color.blue)
                                            .clipShape(Circle())
                                            .foregroundColor(.white)
                                    } )
        }
    }
}

struct DetailView: View {
    var existingItem: ListItem?

    var body: some View {
        Text((existingItem != nil) ? "Edit existing: \(existingItem!.name)" : "Enter NEW List Item")
    }
}

Thank you! By the way, I'm on macOS Catalina 10.15.2 using: Xcode 11.3.1

electromaggot
  • 634
  • 6
  • 16

1 Answers1

10

NavigationLink should be inside NavigationView, not in navigation bar, so the following approach works...

@State private var addMode = false
var body: some View {
    NavigationView {
        VStack {
            List(listItems) { listItem in
                NavigationLink(destination: AddDetailView(existingItem: listItem)) {
                    Text(listItem.name)
                }
            }
            .navigationBarTitle(Text("Configure List Items"), displayMode: .inline)
            .navigationBarItems(trailing: Button(action: { 
                 // button activates link
                  self.addMode = true 
                } ) {
                Image(systemName: "plus")
                    .resizable()
                    .padding(6)
                    .frame(width: 24, height: 24)
                    .background(Color.blue)
                    .clipShape(Circle())
                    .foregroundColor(.white)
            } )

            // invisible link inside NavigationView for add mode
            NavigationLink(destination: AddDetailView(existingItem: nil), 
                isActive: $addMode) { EmptyView() }
        }
    }
}
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • 1
    Is there no built in component for this? – Alexander Jan 16 '20 at 20:41
  • 1
    @Alexander - I'd like to know the same thing! There's `EditButton()` with its associated functionality, and there are some other UI elements where a "plus sign button" is available for add operation, but in the case of this NavigationView, it kind of blew me away that in 2020 I'd be having to roll my own button (even using `Image(systemName:` etc.). – electromaggot Jan 16 '20 at 21:36
  • Thanks for this very useful hackaround! I'm learning SwiftUI and am kind of shocked at the lack of standard widgets, but more shocked at the low quality of Apple's documentation. FWIW there is also `Image(systemName: "plus.circle")` if you want the default circle-add icon, at least as of XCode 12; modifying it with `.font(.title)` and so on is pretty neat. – Kevin Frost Aug 10 '21 at 23:24