Swiftui 中的汉堡导航菜单幻灯片动画

时间:2021-05-10 04:24:22

标签: swift animation swiftui navigation hamburger-menu

我正在尝试为左侧菜单内容构建一个带有幻灯片动画的导航抽屉,为菜单背景构建不透明动画。

除了动画之外,下面的代码对我来说很好用。我不确定动画究竟是哪里出了问题,而且无法正常工作。

这是我的代码。

struct LeftNavigationView:View {
    @EnvironmentObject var viewModel:ViewModel
    var body: some View {
        ZStack {
            Color.black.opacity(0.8)
                .ignoresSafeArea()
                .transition(.opacity)
                .animation(.default)
            VStack {
                Button(action: {
                    self.viewModel.isLeftMenuVisible.toggle()
                }, label: {
                    Text("Close Me")
                })
            }
            .frame(maxWidth:.infinity, maxHeight: .infinity)
            .background(Color.white) 
            .cornerRadius(10)
            .padding(.trailing)
            .padding(.trailing)
            .padding(.trailing)
            .padding(.trailing)
            .transition(
                .asymmetric(
                    insertion: .move(edge: .leading),
                    removal: .move(edge: .leading)
                )
            )
            .animation(.default)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .animation(.default)
    }
}


class ViewModel: ObservableObject {
    @Published var isLeftMenuVisible:Bool = false
}

struct ContentView: View {
    @StateObject var viewModel:ViewModel = ViewModel()
    var body: some View {
        ZStack {
            NavigationView {
                VStack(alignment:.leading) {
                    Button(action: {
                        self.viewModel.isLeftMenuVisible.toggle()
                    }, label: {
                        Text("Button")
                    })
                }.padding(.horizontal)
                .navigationTitle("ContentView")
            }
            if self.viewModel.isLeftMenuVisible {
                LeftNavigationView()
            }
        }.environmentObject(self.viewModel)
    }
}

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

你应该使用这个库KYDrawerController

在 SceneDelegate 中声明 ContentView 和 MenuView:

import KYDrawerController
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    
    var window: UIWindow?
    let drawerController = KYDrawerController(drawerDirection: .left, drawerWidth: 300)
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        
        
        drawerController.mainViewController = UIHostingController(rootView: ContentView())
        drawerController.drawerViewController = UIHostingController(rootView: LeftNavigationView()
                                                                    
        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            let vc = drawerController
            vc.view.frame = window.bounds
            window.rootViewController = vc
            self.window = window
            (UIApplication.shared.delegate as? AppDelegate)?.self.window = window
            window.makeKeyAndVisible()
        }
        //...
    }
    
    //...
}

答案 1 :(得分:1)

你快到了。最好控制菜单视图内的外观/消失。找到下面的固定部分,代码中用注释突出显示的地方。

使用 Xcode 12.5 / iOS 14.5 测试

注意:演示准备打开“模拟器>调试>慢动画”以获得更好的可见性

demo

struct LeftNavigationView:View {
    @EnvironmentObject var viewModel:ViewModel
    var body: some View {
        ZStack {
            if self.viewModel.isLeftMenuVisible {     // << here !!
                Color.black.opacity(0.8)
                    .ignoresSafeArea()
                    .transition(.opacity)

                VStack {
                    Button(action: {
                        self.viewModel.isLeftMenuVisible.toggle()
                    }, label: {
                        Text("Close Me")
                    })
                }
                .frame(maxWidth:.infinity, maxHeight: .infinity)
                .background(Color.white)
                .cornerRadius(10)
                .padding(.trailing)
                .padding(.trailing)
                .padding(.trailing)
                .padding(.trailing)
                .transition(
                    .asymmetric(
                        insertion: .move(edge: .leading),
                        removal: .move(edge: .leading)
                    )
                ).zIndex(1)  // << force keep at top where removed!!
            }
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .animation(.default, value: self.viewModel.isLeftMenuVisible)  // << here !!
    }
}

struct ContentView: View {
    @StateObject var viewModel = ViewModel()
    var body: some View {
        ZStack {
            NavigationView {
                VStack(alignment:.leading) {
                    Button(action: {
                        self.viewModel.isLeftMenuVisible.toggle()
                    }, label: {
                        Text("Button")
                    })
                }.padding(.horizontal)
                .navigationTitle("ContentView")
            }

            // included here, everything else is managed inside (!) view
            LeftNavigationView()

        }.environmentObject(self.viewModel)
    }
}