ios – Problem Navigating to View from Facet Menu in Swiftui

ios – Problem Navigating to View from Facet Menu in Swiftui


I’m presently making a facet menu for an iOS app in SwiftUI and having navigation points. Navigating to a view from the facet menu is ok, however the view will present up contained in the facet menu itself, quite than it being like Twitter, the place the facet menu is dismissed after which the view opens up within the app. I’ve made a reproducible mock of the problem, which will be seen under.

First is the info mannequin for the facet menu:

struct SideMenuOBJ: Identifiable, Hashable {
    let id = UUID()
    let picture: UIImage
    let label: String
    var vc: UIViewController?
}

struct SideMenuRepository {
    static func profile () -> [SideMenuOBJ] {
        let base = [
            SideMenuOBJ(image: UIImage(systemName: "person.circle")!, label: "Profile"),
            SideMenuOBJ(image: UIImage(systemName: "list.clipboard")!, label: "Account Summary"),
            SideMenuOBJ(image: UIImage(systemName: "fossil.shell")!, label: "History")
        ]
        
        return base
    }
}

The Drawer creates the facet menu:

public struct Drawer<Menu: View, Content material: View>: View {
    @Binding personal var isOpened: Bool
    personal let menu: Menu
    personal let content material: Content material
    
    public init(
        isOpened: Binding<Bool>,
        @ViewBuilder menu:  () -> Menu,
        @ViewBuilder content material: () -> Content material
    ) {
        _isOpened = isOpened
        self.menu = menu()
        self.content material = content material()
    }
    
    public var physique: some View {
        ZStack(alignment: .main) {
            content material
            
            if isOpened {
                Shade.clear
                    .contentShape(Rectangle())
                    .onTapGesture {
                        if isOpened {
                            isOpened.toggle()
                        }
                    }
                menu
                    .transition(.transfer(edge: .main))
                    .zIndex(1)
            }
        }
        .animation(.spring(), worth: isOpened)
        .setting(.drawerPresentationMode, $isOpened.mappedToDrawerPresentationMode())
    }
}

public struct DrawerPresentationMode {
    @Binding personal var _isOpened: Bool
    
    init(isOpened: Binding<Bool>) {
        __isOpened = isOpened
    }
    
    public var isOpened: Bool {
        _isOpened
    }
    
    mutating func open() {
        if !_isOpened {
            _isOpened = true
        }
    }
    
    mutating func shut() {
        if _isOpened {
            _isOpened = false
        }
    }
}

extension Binding the place Worth == Bool {
    func mappedToDrawerPresentationMode() -> Binding<DrawerPresentationMode> {
        Binding<DrawerPresentationMode>(
            get: {
                DrawerPresentationMode(isOpened: self)
            },
            set: { newValue in
                self.wrappedValue = newValue.isOpened
            }
        )
    }
}

extension DrawerPresentationMode {
    static var placeholder: DrawerPresentationMode {
        DrawerPresentationMode(isOpened: .fixed(false))
    }
}

personal struct DrawerPresentationModeKey: EnvironmentKey {
    static var defaultValue: Binding<DrawerPresentationMode> = .fixed(.placeholder)
}

extension EnvironmentValues {
    public var drawerPresentationMode: Binding<DrawerPresentationMode> {
        get { self[DrawerPresentationModeKey.self] }
        set { self[DrawerPresentationModeKey.self] = newValue }
    }
}

The view mannequin is fairly easy:

class SideMenuViewModel: ObservableObject {
    @Revealed var profileOptions: [SideMenuOBJ] = SideMenuRepository.profile()
    
    @ViewBuilder
    func handleProfileOptionTap(possibility: SideMenuOBJ?) -> some View {
        swap possibility?.label {
        case "My Profile":
            ProfileView()
        case "Account":
            AccountSummaryView()
        case "My Takes Historical past":
            Historical past()
        default:
            EmptyView()
        }
    }
}

Lastly, right here is the facet menu and the mother or father view that calls the facet menu:

struct SideMenu: View {
    @ObservedObject var viewModel: SideMenuViewModel
    @State personal var selectedOption: SideMenuOBJ?
    @State personal var isNavigating: Bool = false
    
    var physique: some View {
        NavigationStack {
            ZStack {
                ScrollView {
                    VStack(alignment: .main, spacing: 16) {
                        VStack(alignment: .main, spacing: 12) {
                            ForEach(viewModel.profileOptions) { possibility in
                                Button {
                                    selectedOption = possibility
                                    isNavigating.toggle()
                                } label: {
                                    HStack {
                                        Picture(uiImage: possibility.picture)
                                            .renderingMode(.template)
                                            .foregroundColor(.major)
                                            .body(width: 24, top: 24)
                                        Textual content(possibility.label)
                                            .fontWeight(.daring)
                                            .foregroundStyle(Shade.major)
                                            .font(.physique)
                                            .padding(.vertical, 8)
                                            .padding(.horizontal)
                                            .cornerRadius(8)
                                    }
                                    .cornerRadius(8)
                                }
                            }
                        }
                        .padding(.horizontal)
                    }
                }
                .scrollIndicators(.by no means)
            }
            .navigationDestination(merchandise: $selectedOption) { possibility in
                viewModel.handleProfileOptionTap(possibility: possibility)
            }
        }
    }
}
struct SideMenuIssueApp: App {
    @State personal var showSideMenu: Bool = false
    var physique: some Scene {
        WindowGroup {
            Drawer(isOpened: $showSideMenu) {
                ZStack {
                    SideMenu(viewModel: SideMenuViewModel())
                        .body(width: 270)
                }
            } content material: {
                contentView
            }
        }
    }
    
    var contentView: some View {
        NavigationStack {
            TabView {
                ContentView()
                    .tabItem {
                        Label("Content material View", systemImage: "tray")
                    }
            }
            .toolbar {
                ToolbarItem(placement: .topBarLeading) {
                    Button {
                        showSideMenu.toggle()
                    } label: {
                        Picture(systemName: "menucard")
                    }
                }
            }
        }
    }
}

ProfileView, AccountSummaryView, and HistoryView are all default views for navigation testing. What am I doing fallacious regarding the navigation that is making the chosen view present up within the Facet Menu as a substitute of on the app itself? All assistance is tremendously appreciated!

author avatar
roosho Senior Engineer (Technical Services)
I am Rakib Raihan RooSho, Jack of all IT Trades. You got it right. Good for nothing. I try a lot of things and fail more than that. That's how I learn. Whenever I succeed, I note that in my cookbook. Eventually, that became my blog. 
rooshohttps://www.roosho.com
I am Rakib Raihan RooSho, Jack of all IT Trades. You got it right. Good for nothing. I try a lot of things and fail more than that. That's how I learn. Whenever I succeed, I note that in my cookbook. Eventually, that became my blog. 

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here


Latest Articles

author avatar
roosho Senior Engineer (Technical Services)
I am Rakib Raihan RooSho, Jack of all IT Trades. You got it right. Good for nothing. I try a lot of things and fail more than that. That's how I learn. Whenever I succeed, I note that in my cookbook. Eventually, that became my blog.