spoax
spoax

Reputation: 589

Implementing custom sidebar across all views - SwiftUI

OUTLINE

I have made a custom slimline sidebar that I am now implementing across the whole app. The sidebar consists of a main button that is always showing and when pressed it shows or hides the rest of the sidebar that consists of buttons navigating to other views.

I am currently implementing the sidebar across the app on each view by creating a ZStack like this:

struct MainView: View {
    var body: some View {
        ZStack(alignment: .topLeading) {
            SideBarCustom()
            Text("Hello, World!")
        }
    }
}

PROBLEM

I am planning on adding a GeometryReader so if the side bar is shown the rest of the content moves over. With this in mind, the way I am implementing the sidebar on every view feels clunky and a long winded way to add it. Is there a more simple/better method to add this to each view?

Sidebar Code:

struct SideBarCustom: View {
    
    @State var isToggle = false
    
    var names = ["Home", "Products", "Compare", "AR", "Search"]
    var icons = ["house.fill", "printer.fill.and.paper.fill", "list.bullet.rectangle", "arkit", "magnifyingglass"]
    var imgSize = 20
    
    var body: some View {
        GeometryReader { geo in
            VStack {
                Button(action: {
                    self.isToggle.toggle()
                }, label: {
                    Image("hexagons")
                        .resizable()
                        .frame(width: 40, height: 40)
                        .padding(.bottom, 20)
                })
                if isToggle {
                    ZStack{
                        RoundedRectangle(cornerRadius: 5)
                            .foregroundColor(Color.red)
                            .frame(width: 70, height: geo.size.height)                        
                        VStack(alignment: .center, spacing: 60) {
                            ForEach(Array(zip(names, icons)), id: \.0) { item in
                                Button(action: {
                                    // NAVIIGATE TO VIEW
                                }, label: {
                                    VStack {
                                        Image(systemName: item.1)
                                            .resizable()
                                            .frame(width: CGFloat(imgSize), height: CGFloat(imgSize))
                                        Text(item.0)
                                    }
                                })
                            }
                        }
                    }
                }
            }
        }
    }
}

Upvotes: 0

Views: 902

Answers (1)

jnpdx
jnpdx

Reputation: 52347

I don't think there's necessarily a reason to use GeometryReader here. The following is an example that has a dynamic width sidebar (although you could set it to a fixed value) that slides in and out. The main content view resizes itself automatically, since it's in an HStack:

struct ContentView : View {
    @State private var sidebarShown = false
    
    var body: some View {
        HStack {
            if sidebarShown {
                CustomSidebar(sidebarShown: $sidebarShown)
                    .frame(maxHeight: .infinity)
                    .border(Color.red)
                    .transition(sidebarShown ? .move(edge: .leading) : .move(edge: .trailing) )
            }
            ZStack(alignment: .topLeading) {
                MainContentView()
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                if !sidebarShown {
                    Button(action: {
                        withAnimation {
                            sidebarShown.toggle()
                        }
                    }) {
                        Image(systemName: "info.circle")
                    }
                }
            }
        }
    }
}

struct CustomSidebar : View {
    @Binding var sidebarShown : Bool
    
    var body: some View {
        VStack {
            Button(action: {
                withAnimation {
                    sidebarShown.toggle()
                }
            }) {
                Image(systemName: "info.circle")
            }
            Spacer()
            Text("Hi")
            Text("There")
            Text("World")
            Spacer()
        }
    }
}

struct MainContentView: View {
    var body: some View {
        VStack {
            Text("Main content")
        }
    }
}

Upvotes: 1

Related Questions