Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI ContextMenu navigation to another view

Tags:

swiftui

I am trying to get a context menu to navigate to another view using the following code

var body: some View
{
    VStack
    {
        Text(self.event.name).font(.body)
        ...
        Spacer()
        NavigationLink(destination: EditView(event: self.event))
        {
            Image(systemName: "pencil")
        }
    }
    .navigationBarTitle(Text(appName))
    .contextMenu
    {
        NavigationLink(destination: EditView(event: self.event))
        {
            Image(systemName: "pencil")
        }
    }
}

The NavigationLink within the VStack works as expected and navigates to the edit view but I want to use a contextMenu. Although the context menu displays the image, when I tap on it it doesn't navigate to the edit view, instead it just cancels the context menu.

I am doing this within a watch app but don't think that should make a difference, is there anything special I have to do with context menu navigation?

like image 799
CodeChimp Avatar asked Oct 07 '19 14:10

CodeChimp


3 Answers

In Xcode 11.4 it's now possible to do this with sensible NavigationLink buttons. Yay! ๐ŸŽ‰

.contextMenu {
    NavigationLink(destination: VisitEditView(visit: visit)) {
        Text("Edit visit")
        Image(systemName: "square.and.pencil")
    }
    NavigationLink(destination: SegmentsEditView(timelineItem: visit)) {
        Text("Edit individual segments")
        Image(systemName: "ellipsis")
    }
}
like image 26
sobri Avatar answered Jan 02 '23 22:01

sobri


I would use the isActive variant of NavigationLink that you can trigger by setting a state variable. Apple documents this here

This variant of NavigationLink is well fit for dynamic/programatic navigation.

Your .contextMenu sets the state variable to true and that activates the NavigationLink. Because you don't want the link to be visible, set the label view to EmptyView

Here's an example, not identical to your post but hopefully makes it clear.

struct ContentView: View {

    @State private var showEditView = false

    var body: some View {

        NavigationView {
            VStack {
                Text("Long Press Me")
                    .contextMenu {
                        Button(action: {
                            self.showEditView = true
                        }, label: {
                            HStack {
                                Text("Edit")
                                Image(systemName: "pencil")
                            }
                        })
                }
                NavigationLink(destination: Text("Edit Mode View Here"), isActive: $showEditView) {
                    EmptyView()
                }
            }
            .navigationBarTitle("Context Menu")
        }
    }
}
like image 154
KB-YYZ Avatar answered Jan 02 '23 23:01

KB-YYZ


This works on Xcode 11.6

struct ContentView: View {
    
    @State var isActiveFromContextMenu = false
    var body: some View {
        NavigationView{
            VStack{
                NavigationLink(destination : detailTwo(), isActive: $isActiveFromContextMenu ){
                    EmptyView()
                }
                
                List{
                    NavigationLink(destination: detail() ){
                        row(isActiveFromContextMenu: $isActiveFromContextMenu)
                    }
                    NavigationLink(destination: detail() ){
                        row(isActiveFromContextMenu: $isActiveFromContextMenu)
                    }
                    NavigationLink(destination: detail() ){
                        row(isActiveFromContextMenu: $isActiveFromContextMenu)
                    }
                }
            }       
        }   
    }    
}

struct detail: View {
    var body: some View{
        Text("Detail view")
    }
}

struct detailTwo: View {
    var body: some View{
        Text("DetailTwo view")
    }
}

struct row: View {
    
    @Binding var isActiveFromContextMenu : Bool
    var body: some View {
        
        HStack{
            
            Text("item")
            
        }.contextMenu{
            Button(action: {
                self.isActiveFromContextMenu = true
            })
            {
                Text("navigate to")
            }
        }
    }
}