在SwiftUI中的NavigationBarItem菜单中展示不同的视图

3

我试图根据导航栏菜单中选择的选项显示不同的视图,但卡在了最佳实现方式上。 首先,基于我的当前做法(我认为它不正确!),当我按下菜单项时,在Xcode调试器中会收到以下信息:

SideMenu[16587:1131441] [UILog] Called -[UIContextMenuInteraction updateVisibleMenuWithBlock:] while no context menu is visible. This won't do anything.

我该如何解决这个问题?

第二,当我从菜单中选择一个选项时,我该如何重置布尔值,以便它不会再次执行,除非再次从菜单中选择。尝试在if条件内使用self.showNewView = false进行重置会导致编译器错误。

这是我正在处理的完整可执行样本代码。感谢任何帮助解决此问题。谢谢!

struct ContentView: View {
    @State var showNewView = false
    @State var showAddView = false
    @State var showEditView = false
    @State var showDeleteView = false
    
    var body: some View {
        NavigationView {
            GeometryReader { g in
                VStack {
                    if self.showAddView {
                        AddView()
                    }
                    if self.showNewView {
                        NewView()
                    }
                    if self.showEditView {
                        EditView()
                    }
                    if self.showDeleteView {
                        DeleteView()
                    }
                }.frame(width: g.size.width, height: g.size.height)
            }
            .navigationTitle("Title")
            .navigationBarItems(leading: {
                Menu {
                    Button(action: {showNewView.toggle()}) {
                        Label("New", systemImage: "pencil")
                    }
                    Button(action: {showEditView.toggle()}) {
                        Label("Edit", systemImage: "square.and.pencil")
                    }
                } label: {
                    Image(systemName: "ellipsis.circle")
                }
            }(), trailing: {
                Menu {
                    Button(action: {showAddView.toggle()}) {
                        Label("Add", systemImage: "plus")
                    }
                    Button(action: {showDeleteView.toggle()}) {
                        Label("Delete", systemImage: "trash")
                    }
                } label: {
                    Image(systemName: "plus")
                }
            }())
        }
        .navigationBarTitleDisplayMode(.inline)
        .navigationViewStyle(StackNavigationViewStyle())
    }
}



struct NewView: View {
    var body: some View {
        GeometryReader { g in
                Text("This is New View")
        }
        .background(Color.red)
    }
}

struct EditView: View {
    var body: some View {
        GeometryReader { g in
            Text("This is Edit View")
        }
        .background(Color.green)
    }
}

struct AddView: View {
    var body: some View {
        GeometryReader { g in
            Text("This is Add View")
        }
        .background(Color.orange)
    }
}

struct DeleteView: View {
    var body: some View {
        GeometryReader { g in
            Text("This is Delete View")
        }
        .background(Color.purple)
    }
}

当我选择每个菜单项时,会显示如下内容。我想只显示一个菜单项,也就是在选择新的菜单项时隐藏其他菜单项。

输入图像描述

输入图像描述


你写了navigate,但在你的代码中只是显示/隐藏子视图,那么你真正想做什么? - Asperi
我想展示所选的视图。例如,如果我从菜单中选择“新建”,我希望切换到“新建视图”。 - RXP
更新主题为“显示不同视图”。 - RXP
1个回答

2

一个可能的解决方案是使用专用的枚举来表示你的当前视图(而不是四个@State属性):

enum CurrentView {
    case new, add, edit, delete
}

@State var currentView: CurrentView?

请注意,您还可以将代码部分提取到计算属性中。
以下是完整的代码:
enum CurrentView {
    case new, add, edit, delete
}

struct ContentView: View {
    @State var currentView: CurrentView?

    var body: some View {
        NavigationView {
            GeometryReader { g in
                content
                    .frame(width: g.size.width, height: g.size.height)
            }
            .navigationTitle("Title")
            .navigationBarTitleDisplayMode(.inline)
            .navigationBarItems(leading: leadingBarItems, trailing: trailingBarItems)
        }
        .navigationViewStyle(StackNavigationViewStyle())
    }
    
    @ViewBuilder
    var content: some View {
        if let currentView = currentView {
            switch currentView {
            case .add:
                AddView()
            case .new:
                NewView()
            case .edit:
                EditView()
            case .delete:
                DeleteView()
            }
        }
    }
    
    var leadingBarItems: some View {
        Menu {
            Button(action: { currentView = .new }) {
                Label("New", systemImage: "pencil")
            }
            Button(action: { currentView = .edit }) {
                Label("Edit", systemImage: "square.and.pencil")
            }
        } label: {
            Image(systemName: "ellipsis.circle")
        }
    }
    
    
    var trailingBarItems: some View {
        Menu {
            Button(action: { currentView = .add }) {
                Label("Add", systemImage: "plus")
            }
            Button(action: { currentView = .delete }) {
                Label("Delete", systemImage: "trash")
            }
        } label: {
            Image(systemName: "plus")
        }
    }
}

谢谢你的回答!你很好地组织了代码并解决了第二个问题。然而,我仍然在调试窗口中看到警告:“SideMenu[1282:33494] [UILog] Called -[UIContextMenuInteraction updateVisibleMenuWithBlock:] while no context menu is visible. This won't do anything”。有没有什么指针可以解决这个问题?如果有的话,我就可以接受你的答案了。 - RXP
@RXP 这是一些内部警告/错误信息,但看起来它并不影响任何东西。即使您创建一个仅包含菜单的空项目/视图,您也会看到这个警告。您可以忽略它。 - pawello2222
谢谢,希望他们能修复这个问题。看到调试窗口中的警告很恼人。 - RXP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接