SwiftUI 中的侧边菜单栏

时间:2021-04-07 20:17:07

标签: swift swiftui

我想在 SwiftUI 中创建一个侧边菜单栏。

// 下面是我想用于内容视图的自定义栏视图的代码。

VStack {
            ZStack {
                VStack {
                    Button(action: {
                        withAnimation {
                            sidebarShowns.toggle()
                        }
                    }) {
                        Image(systemName: "line.horizontal.3")
                            .font(.headline)
                        }.padding(.leading)
                    }.frame(maxWidth: .infinity, alignment: .leading)
                    
                    Text("WeCollab")
                        .foregroundColor(.white)
                        .font(.title)
                }
                .background(Color.purple.edgesIgnoringSafeArea(.top))
       }
}

我希望侧边菜单栏视图利用这个自定义栏,一旦用户点击 3 条水平线图标,自定义侧边菜单栏就会在屏幕左侧打开。

我希望它可以这样工作,一旦通过点击 3 个水平线图标打开侧边菜单栏,用户会看到 3 个按钮,例如设置、主要和关于我们。一旦用户点击“关于我们”,“关于我们”视图就会在 iPhone 屏幕上完全打开,自定义栏会隐藏,侧边菜单会自动关闭。用户将使用后退按钮导航回原始视图“此后退按钮使用左 V 形图标”。

我不希望每个视图上都有自定义栏,也不想每个视图中的侧边菜单。

我希望能够为每个视图使用一个 SwiftUI 视图文件来执行此操作,该文件将被链接以作为侧菜单栏中的按钮到达每个视图。

//我有一些代码的例子,但没有按照我想要的方式工作。

import SwiftUI

enum ViewTypesz {
    case main
    case settings
    case aboutUs
    
}

class SidebarNavigationManagerz : ObservableObject {
    @Published var viewType : ViewTypesz = .main
}


struct testView: View {
    @State private var sidebarShowns = false
    @StateObject var navigationManagers = SidebarNavigationManagerz()
    
    var body: some View {
        ZStack(alignment: .topLeading) {
            if sidebarShowns {
                SidebarView(navigationManagers: navigationManagers)
                    .frame(width: 250)
                    .frame(maxHeight: .infinity)
                    .border(Color.red)
                    .transition(sidebarShowns ? .move(edge: .leading) : .move(edge: .trailing) )
                        .background(customBlueColour)
                        .opacity(60.0)
                        }
        VStack {
            ZStack {
                VStack {
                    Button(action: {
                        withAnimation {
                            sidebarShowns.toggle()
                        }
                    }) {
                        Image(systemName: "line.horizontal.3")
                            .font(.headline)
                        }.padding(.leading)
                    }.frame(maxWidth: .infinity, alignment: .leading)
                    
                    Text("WeCollab")
                        .foregroundColor(.white)
                        .font(.title)
                }
                .background(Color.purple.edgesIgnoringSafeArea(.top))
                
                VStack {
                    switch navigationManagers.viewType {
                    case .main:
                        MainView()
                    case .settings:
                        SettingsViewz(navigationManagers: navigationManagers)
                    case .aboutUs:
                        AboutUsView()
                   // case .homeview:
                     //   HomeView()
                    }
                }.frame(maxHeight: .infinity)
            }.frame(maxWidth: .infinity, maxHeight: .infinity)
            
        }                                .edgesIgnoringSafeArea(.top)

        
    }
}

struct SidebarView : View {
    @ObservedObject var navigationManagers : SidebarNavigationManagerz
    
    var body: some View {
        //Sidebar
        VStack {
            Button(action: { navigationManagers.viewType = .main }) {
                Text("Main")
            }
            Button(action: { navigationManagers.viewType = .settings }) {
                Text("Settings")
            }
            Button(action: { navigationManagers.viewType = .aboutUs }) {
                Text("About Us")
            }
        }
    }
}

struct MainView : View {
    var body: some View {
        Text("Main")
            
    }
}

struct SettingsViewz: View {
    @ObservedObject var navigationManagers : SidebarNavigationManagerz
    
    var body: some View {
        Text("Settings")
        Button("Go home") {
            navigationManagers.viewType = .settings
        }
    }
}

struct AboutUsView : View {
    var body: some View {
        Text("About Us")
    }
}
struct testView_Previews: PreviewProvider {
    static var previews: some View {
        testView()
    }
}

这里是我找到的解决方案的链接,但我无法使其按照我想要的方式工作,但有所帮助。 https://stackoverflow.com/a/66933468/15284614

1 个答案:

答案 0 :(得分:0)

这似乎符合您的要求:


enum ViewTypesz {
    case main
    case settings
    case aboutUs
    
}

class SidebarNavigationManagerz : ObservableObject {
    @Published var viewType : ViewTypesz = .main
    @Published var sidebarShown = false
    
    func navigateToViewType(_ type: ViewTypesz) {
        viewType = type
        sidebarShown = false
    }
    
    @ViewBuilder var viewForType : some View {
        switch viewType {
        case .main:
            EmptyView()
        case .aboutUs:
            AboutUsView()
        case .settings:
            SettingsViewz()
        }
    }
    
    var bindingForNavLink : Binding<Bool> {
        .init { () -> Bool in
            return self.viewType != .main
        } set: { (newValue) in
            if !newValue { self.viewType = .main }
        }

    }
}


struct ContentView: View {
    @StateObject var navigationManagers = SidebarNavigationManagerz()
    
    var body: some View {
        NavigationView {
            if navigationManagers.viewType != .main {
                NavigationLink(destination: navigationManagers.viewForType, isActive: navigationManagers.bindingForNavLink, label: { EmptyView() })
            }
            
            VStack(alignment: .leading) {
                ZStack {
                    VStack {
                        Button(action: {
                            withAnimation {
                                navigationManagers.sidebarShown.toggle()
                            }
                        }) {
                            Image(systemName: "line.horizontal.3")
                                .font(.headline)
                        }.padding(.leading)
                    }.frame(maxWidth: .infinity, alignment: .leading)
                    
                    Text("WeCollab")
                        .foregroundColor(.white)
                        .font(.title)
                }
                .background(Color.purple.edgesIgnoringSafeArea(.top))
                
                ZStack(alignment: .topLeading) {
                    VStack(alignment: .center) {
                        MainView()
                    }
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    
                    if navigationManagers.sidebarShown {
                        SidebarView(navigationManagers: navigationManagers)
                            .frame(width: 250)
                            .frame(maxHeight: .infinity)
                            .border(Color.red)
                            .transition(navigationManagers.sidebarShown ? .move(edge: .leading) : .move(edge: .trailing) )
                            .background(Color.white)
                            .opacity(60.0)
                    }
                }
            }.frame(maxWidth: .infinity, maxHeight: .infinity)
            .navigationBarHidden(true)
        }.navigationViewStyle(StackNavigationViewStyle())
    }
}

struct SidebarView : View {
    @ObservedObject var navigationManagers : SidebarNavigationManagerz
    
    var body: some View {
        VStack {
            Button(action: { navigationManagers.navigateToViewType(.aboutUs) }) {
                Text("About us")
            }
            Button(action: { navigationManagers.navigateToViewType(.settings) }) {
                Text("Settings")
            }
        }
    }
}

struct MainView : View {
    var body: some View {
        Text("Main")
        
    }
}

struct SettingsViewz: View {
    var body: some View {
        Text("Settings")
    }
}

struct AboutUsView : View {
    var body: some View {
        Text("About Us")
    }
}

工作原理:

  1. SidebarNavigationManagerz 维护侧边栏是否显示以及另一个视图的 NavigationLink 是否处于活动状态(通过自定义绑定)
  2. 主视图具有侧边栏和自定义标题以及隐藏的 NavigationView 标题
  3. 侧边栏链接触发 navigateToViewType
  4. 主页上有一个 NavigationLink 仅在导航管理器中的视图类型设置为除 .main 以外的其他内容时才处于活动状态

目前有一个过渡,当我回到主视图时,标题不是立即可见的,我并不为之疯狂,但这是您可以关注的细节工作。这应该会让你走上正确的道路