iosxcodenavigationswiftuiside-menu

How to navigate from side menu in SwiftUI to new view


I am working on app which has home view with navigation and side menu. Side menu has 2 levels menu i.e. each menu entries has sub menu(s). Whenever user click on any side sub-menu, app should display new view but i am unable to achieve this behavior. I tried Navigation view in sub-menu but then sub-menu is broken, i also tried to navigateTo but it also did not work.

This is home view which has attached side menu -

struct HomePageView: View {
    @State var size = UIScreen.main.bounds.width / 1.6
    
    var body: some View {
       GeometryReader{ geometry in
            NavigationView{
                VStack{
                    ScrollView (.vertical, showsIndicators: true) {
                        anotherView()
                        HStack{
                            Spacer(minLength: 0)
                        }
                    }.frame(width: geometry.size.width)
                }
                .background(Image("background").resizable().scaledToFill().clipped())
                .animation(.spring()).background(Color.lairBackgroundGray)
                .navigationBarItems(leading: Button(action: {
                    self.size = 10
                }, label: {
                    Image("menu")
                        .resizable()
                        .frame(width: 30, height: 30)
                }).foregroundColor(.appHeadingColor), trailing:
                    Button(action: {
                        withAnimation {
                            print("profile is pressed")
                        }
                    }) {
                        HStack {
                            NavigationLink(destination: ProfileView()) {
                                LinearGradient.lairHorizontalDark
                                    .frame(width: 30, height: 30)
                                    .mask(
                                        Image(systemName: "person.crop.circle")
                                            .resizable()
                                            .scaledToFit()
                                )
                            }
                        }
                    }
                ).navigationBarTitle("Home", displayMode: .inline)
                 .animation(.spring())
                }.padding(.top, UIApplication.shared.windows.first?.safeAreaInsets.top)
            HStack{
                menu(size: self.$size)  // --> Side menu
                    .cornerRadius(20)
                    .padding(.leading, -self.size)
                    .offset(x: -self.size)
                Spacer().background(Color.lairBackgroundGray)
            }.padding(.top, UIApplication.shared.windows.first?.safeAreaInsets.top)
            .animation(.spring())
           }
    }
}

Below is side menu view, it is created based on State variable -

struct menu : View {
    @Binding var size : CGFloat
    @State var logout: Bool = false
    @State private var didSubMenuPressed: Bool = false
    
    @State var sideMenuEntries = [
        SideMenuData(index: 0, imageName: "info.circle",
                     menuText: "Info",
                     subMenu: ["Info1", "Info2", "Info3", "Info4"],
                     expand: false),
        SideMenuData(index: 1, imageName: "doc.on.doc",
                     menuText: "Documents",
                     subMenu: ["Documents1", "Documents2"],
                     expand: false)
    ]
    
    var body : some View{
        VStack (alignment: .leading){
            HStack{
                Spacer()
                Button(action: {
                    self.size =  UIScreen.main.bounds.width / 1.6
                }) {
                    Image("close").resizable()
                        .frame(width: 15, height: 15)
                        .padding()
                }
                .foregroundColor(.white)
                .clipShape(Circle())
            }
            ForEach (sideMenuEntries.indices) { index in
                VStack (alignment: .leading, spacing: 0, content: {
                    HStack{
                        Image(self.sideMenuEntries[index].imageName).resizable().frame(width: 25, height: 25)
                            .foregroundColor(.white)
                        Text(self.sideMenuEntries[index].menuText).fontWeight(.heavy).foregroundColor(.white)
                        if self.sideMenuEntries[index].subMenu.count > 1 {
                            Image(systemName: self.sideMenuEntries[index].expand ? "chevron.compact.up" : "chevron.compact.down")
                                .resizable()
                                .frame(width: 10, height: 10)
                                .foregroundColor(.white)
                        }
                        
                        Image("logout-1").resizable().frame(width: 25, height: 25)//.padding(.leading, 5)
                            .foregroundColor(.white)
                        Text(self.sideMenuEntries[index].menuText).fontWeight(.heavy).foregroundColor(.white)
                        if self.logout {
                            //
                        }
                        
                    }
                    .contentShape(Rectangle())
                    .onTapGesture {
                        self.sideMenuEntries[index].expand.toggle()
                    }
                    if self.sideMenuEntries[index].expand {
                        VStack (alignment: .leading){
                            ForEach (self.sideMenuEntries[index].subMenu.indices) { index1 in
                                Button(action: {
                                    print("\(self.sideMenuEntries[index].subMenu[index1]) is pressed")
                                    self.size =  UIScreen.main.bounds.width / 1.6
                                    self.didSubMenuPressed.toggle()
                                }){
                                    Text(self.sideMenuEntries[index].subMenu[index1])
                                        .foregroundColor(.white)
                                }
                                .padding([.top, .bottom], 7)
                            }
                        }
                        .padding(.top, 14)
                        .padding(.leading, 34)
                    }
                })
            }
            Spacer()
        }
        .padding(.leading, 40)
        .frame(width: UIScreen.main.bounds.width / 1.3)
        .background(LinearGradient(
            gradient: Gradient(
                colors: [.buttonGradientStartColor, .buttonGradientEndColor]),
            startPoint: .top,
            endPoint: .bottom))
        // if u want to change swipe menu background color
    }
}

Solution

  • I found a way to achieve this behavior , create State var in HomePageview and Binding var in menu and that resolved my problem.