13

Can you use a NavigationLink as a Menu's item in swiftUI?

It seems to do just nothing:

Menu {
   NavigationLink(destination: Text("test1")) {
       Text("item1")
   }
   NavigationLink(destination: Text("test2")) {
       Text("item2")
   }
} label: {
   Text("open menu")
}

In case it is meant to not work as tried above, is there an alternative way of achiving the intended reult?

Leo
  • 1,508
  • 13
  • 27

2 Answers2

15

init(destination:isActive:label:) is deprecated since iOS 16

'init(destination:isActive:label:)' was deprecated in iOS 16.0: use NavigationLink(value:label:) inside a NavigationStack or NavigationSplitView

NavigationLink should be inside NavigationView hierarchy. The Menu is outside navigation view, so put buttons inside menu which activate navigation link placed inside navigation view, eg. hidden in background.

Here is a demo of possible approach (tested with Xcode 12.1 / iOS 14.1)

demo

struct DemoNavigateFromMenu: View {
    @State private var navigateTo = ""
    @State private var isActive = false
    var body: some View {
        NavigationView {
            Menu {
                Button("item1") {
                    self.navigateTo = "test1"
                    self.isActive = true
                }
                Button("item2") {
                    self.navigateTo = "test2"
                    self.isActive = true
                }
            } label: {
                Text("open menu")
            }
            .background(
                NavigationLink(destination: Text(self.navigateTo), isActive: $isActive) {
                    EmptyView()
                })
        }
    }
}
Vyacheslav
  • 26,359
  • 19
  • 112
  • 194
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • Works just fine, I assume that using the isActive binding is the (only/best-practice) approach for navigating to a different view programmatically in swiftUI? – Leo Nov 15 '20 at 14:57
3

I can say that Asperi's answer is great solution. It helped a lot. But we need a custom view to hold a reference inside the destination property right? not a string.

@State var navigateTo: AnyView?
@State var isNavigationActive = false

We can hold a reference AnyView type and then call the view like this:

Menu {
    Button {
        navigateTo = AnyView(CreateItemView())
        isNavigationActive = true
    } label: {
        Label("Create an Item", systemImage: "doc")
    }
    
    Button {
        navigateTo = AnyView(CreateItemView())
        isNavigationActive = true
    } label: {
        Label("Create a category", systemImage: "folder")
    }
} label: {
    Label("Add", systemImage: "plus")
}

For more detail please see this post: https://developer.apple.com/forums/thread/119583

fhe
  • 6,099
  • 1
  • 41
  • 44
fatihios
  • 31
  • 2