无需容器ViewController与CocoaPods:在已有UIKit单页应用中集成侧边菜单的实现方案咨询
不用容器ViewController实现侧边菜单的方案
嘿,完全理解你不想动现有架构、不想引入第三方库的想法——毕竟项目代码量不小,重构容器VC的成本确实很高。这里给你一个纯原生、不用容器VC的实现思路,亲测可行:
核心思路
直接把侧边菜单ViewController的视图添加到主窗口(或导航控制器视图)上,通过修改视图位置配合UIKit动画实现滑入滑出,全程不用嵌套容器VC。
具体步骤
1. 准备侧边菜单VC
- 在Storyboard里给你的侧边菜单VC设置一个唯一的
Storyboard ID(比如SideMenuVC),方便后续初始化。 - 在你的主ViewController里添加一个属性,用来持有侧边菜单VC的引用(避免被提前释放):
private var sideMenuVC: SideMenuViewController?
2. 初始化并配置菜单视图
在你点击左上角BarButtonItem的触发方法里,先初始化菜单VC(只初始化一次):
@IBAction func toggleSideMenu(_ sender: UIBarButtonItem) { // 如果菜单还没初始化,先创建实例 if sideMenuVC == nil { sideMenuVC = storyboard?.instantiateViewController(withIdentifier: "SideMenuVC") guard let menuView = sideMenuVC?.view else { return } // 配置菜单视图初始位置:左侧完全隐藏 let menuWidth = UIScreen.main.bounds.width * 0.8 // 菜单宽度设为屏幕80%,可调整 menuView.frame = CGRect( x: -menuWidth, y: 0, width: menuWidth, height: UIScreen.main.bounds.height ) // 给菜单加阴影,提升视觉层次 menuView.layer.shadowColor = UIColor.black.cgColor menuView.layer.shadowOpacity = 0.3 menuView.layer.shadowOffset = CGSize(width: 2, height: 0) // 将菜单视图添加到主窗口(如果希望菜单在导航栏上方,用这个;如果要在导航栏下方,换成navigationController?.view.addSubview(menuView)) UIApplication.shared.windows.first?.addSubview(menuView) } // 切换菜单显示/隐藏状态 toggleMenuAnimation() }
3. 实现滑入滑出动画
添加动画方法,修改菜单视图的x坐标来实现滑入:
private func toggleMenuAnimation() { guard let menuView = sideMenuVC?.view else { return } let menuWidth = menuView.bounds.width UIView.animate(withDuration: 0.3, curve: .easeInOut) { // 根据当前位置判断是显示还是隐藏 if menuView.frame.origin.x < 0 { // 滑入:x坐标设为0 menuView.frame.origin.x = 0 // 给主视图添加点击遮罩,点击空白处关闭菜单 self.addTapToCloseMenu() } else { // 滑出:x坐标设为负的菜单宽度 menuView.frame.origin.x = -menuWidth // 移除点击遮罩 self.removeTapToCloseMenu() } } }
4. 添加点击空白关闭菜单的逻辑
实现点击遮罩关闭菜单的辅助方法:
private func addTapToCloseMenu() { let tapGesture = UITapGestureRecognizer(target: self, action: #selector(closeMenu)) // 给主窗口加遮罩视图,或者直接给主VC的view加手势(注意要让手势能响应) let maskView = UIView(frame: UIScreen.main.bounds) maskView.backgroundColor = UIColor.black.withAlphaComponent(0.5) maskView.tag = 999 // 标记遮罩视图,方便后续移除 UIApplication.shared.windows.first?.addSubview(maskView) maskView.addGestureRecognizer(tapGesture) } private func removeTapToCloseMenu() { UIApplication.shared.windows.first?.viewWithTag(999)?.removeFromSuperview() } @objc private func closeMenu() { toggleMenuAnimation() }
5. 内存管理注意事项
在主VC的deinit方法里,记得清理菜单视图和VC引用,避免内存泄漏:
deinit { sideMenuVC?.view.removeFromSuperview() sideMenuVC = nil }
额外优化点
- 如果你的项目用Auto Layout而不是frame,可以给菜单视图添加leading约束到父视图,初始值设为
-menuWidth,动画时把约束的constant改成0,这样适配不同屏幕更灵活。 - 如果侧边菜单需要处理导航跳转(比如跳转到设置页),可以通过获取根导航控制器来实现:
let rootNav = UIApplication.shared.windows.first?.rootViewController as? UINavigationController rootNav?.pushViewController(settingVC, animated: true)
这样一来,你完全不用改动现有导航控制器的结构,也不用引入任何第三方库,就能实现侧边菜单的滑入滑出效果啦!
内容的提问来源于stack exchange,提问作者blendstylez
相关产品推荐
相关产品推荐

