【问题标题】:SwiftUI ContextMenu navigation to another viewSwiftUI ContextMenu 导航到另一个视图
【发布时间】:2019-10-07 14:20:48
【问题描述】:

我正在尝试使用以下代码获取上下文菜单以导航到另一个视图

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")
        }
    }
}

VStack 中的NavigationLink 按预期工作并导航到编辑视图,但我想使用contextMenu。虽然上下文菜单显示图像,但当我点击它时,它不会导航到编辑视图,而是取消上下文菜单。

我在手表应用程序中执行此操作,但认为这不会有什么不同,我对上下文菜单导航有什么特别需要做的吗?

【问题讨论】:

  • 这个周末我已经经历了好几个小时的痛苦,试图让导航正常工作。我得出的结论是 SwiftUI 远未完成,尤其是缺少导航并且存在奇怪的错误/副作用。
  • NavigationView 中嵌入VStack 有帮助吗?
  • @meaning-matters - VStack 没有区别,我尝试了许多不同的方法来做到这一点,但没有成功,这是最干净的。不过感谢您的建议。
  • 我只能祝你好运!

标签: swiftui


【解决方案1】:

在 Xcode 11.4 中,现在可以使用合理的 NavigationLink 按钮来执行此操作。耶! ?

.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")
    }
}

【讨论】:

  • 您能详细说明一下吗?我在 Xcode 11.4 中没有成功。
  • 我在此处发布的代码是来自我的应用程序的精确复制粘贴。所以该代码对我有用。尝试后会发生什么?
  • 对不起,我想通了。我没有将您的 NavigationLinks 包装在 NavigationView 中,呵呵。谢谢!
  • 然而,新的挑战。如果显示 contextMenu 的对象本身包装在 NavigationLink 中,它对我不起作用。也就是说,当我单击“foo”时, NavigationView { NavigationLink(destination: EmptyView()) { Text("foo").contextMenu { NavigationLink(destination: EmptyView()) { Text("bar") } } } } 有效,但不是当我在 contextMenu 中单击“栏”时。
  • 不,同样的结果,不幸的是,无论目的地是 EmptyView()、文本视图还是 DestinationView()。如果显示 contextMenu 的对象也包含在 NavigationLink 中,则 contextMenu 项上的 NavigationLink 将不会导航到其目的地。
【解决方案2】:

我会使用 NavigationLink 的 isActive 变体,您可以通过设置状态变量来触发它。 Apple documents this here

NavigationLink 的这种变体非常适合动态/程序化导航。

您的 .contextMenu 将状态变量设置为 true 并激活 NavigationLink。因为您不希望链接可见,请将label 视图设置为EmptyView

这是一个示例,与您的帖子不同,但希望能够清楚地说明。

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")
        }
    }
}

【讨论】:

  • 我实现了这个,我无法让 NavigationLink 显示文本。我在按钮中放置了一个打印语句(动作所以知道它正在被触发但仍然没有乐趣。
  • 更多调查显示问题是 EmptyView。如果我将它更改为 NavigationLink(destination: EditView(event: self.event), isActive: $showEditView) {Text("Edit")} 它可以工作,但显然上下文菜单的整个想法是我不想要按钮一直显示。
  • 您在视图层次结构中的哪里有 NavigationLink? EmptyView() 在我使用的每个示例中都有效,但可能取决于它所在的位置?
  • 我将它添加到 VStack 中,与您的示例相同。另一点需要注意的是,WatchOS 不支持 NavigationView,因此 VStack 是我在 View 中的顶层。
  • 太棒了。我没有意识到 EmptyView 在 watchOS 上不起作用。关于 .hidden() 的好提示
【解决方案3】:

这适用于 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")
            }
        }
    }
}

【讨论】:

    【解决方案4】:

    我发现成功地在后台屏蔽 NavigationLink 并使用 Button 作为最短但最简单的替代方案切换上下文。

    struct ContentView: View {
        @State private var isShowing = false
    
        var body: some View {
            NavigationView {
                Text("Hello")
                    .background(NavigationLink("", destination: Text("World!"), isActive: $isShowing))
                    .contextMenu {
                        Button {
                            isShowing = true
                        } label: {
                            Label("Switch to New View", systemImage: "chevron.forward")
                        }
                    }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-21
      相关资源
      最近更新 更多