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

Hamburger Navigation Menu Slide Animation in Swiftui

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

除了动画之外,下面的代码对我来说工作正常。我不确定动画到底哪里出错了,它不工作。

这是我的代码。

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)
    }
}

任何帮助将不胜感激。

你应该使用这个库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()
        }
        //...
    }
    
    //...
}

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

测试 Xcode 12.5 / iOS 14.5

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

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)
    }
}