iOS自定义unwind segue动画:实现汉堡菜单返回左滑退出
解决iOS汉堡菜单返回时左侧滑出动画的方案
我明白你现在的痛点——好不容易实现了汉堡菜单从左侧滑入的效果,但系统默认的返回动画还是向右滑出,和菜单的进入逻辑完全不匹配,而且自动生成的返回按钮没法直接通过segue修改动画。这里有几个实用的解决方向,你可以根据自己的场景选择:
方向1:自定义返回按钮,完全掌控动画逻辑
系统自动生成的返回按钮绑定的是默认的pop行为,很难直接修改它的动画。最简单的办法就是替换掉这个按钮,自己实现点击后的动画和页面跳转:
override func viewDidLoad() { super.viewDidLoad() // 替换系统返回按钮为自定义按钮 let customBackButton = UIBarButtonItem( image: UIImage(named: "your-back-icon"), // 用你自己的返回图标 style: .plain, target: self, action: #selector(onBackButtonTapped) ) navigationItem.leftBarButtonItem = customBackButton // 去掉系统自带的返回文字 navigationItem.backButtonTitle = "" } @objc private func onBackButtonTapped() { // 执行左侧滑出的自定义动画 UIView.animate(withDuration: 0.3, animations: { self.view.frame.origin.x = -UIScreen.main.bounds.width }) { [weak self] finished in guard finished else { return } // 动画结束后,无动画地pop回原页面 self?.navigationController?.popViewController(animated: false) } }
这种方式的好处是逻辑简单,不需要依赖系统的导航动画,完全由你自己控制。
方向2:自定义导航控制器的pop动画
如果希望整个导航栈的返回动画都统一为左侧滑出,或者不想替换返回按钮,可以通过自定义导航控制器的代理来实现全局动画控制:
首先创建一个自定义的动画控制器类,实现UIViewControllerAnimatedTransitioning协议:
class LeftSlideOutTransition: NSObject, UIViewControllerAnimatedTransitioning { // 动画时长 func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.3 } // 具体动画逻辑 func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let fromVC = transitionContext.viewController(forKey: .from), let toVC = transitionContext.viewController(forKey: .to) else { transitionContext.completeTransition(false) return } let container = transitionContext.containerView container.addSubview(toVC.view) // 初始状态:原页面在左侧,当前菜单页面在屏幕内 toVC.view.frame.origin.x = -container.bounds.width fromVC.view.frame.origin.x = 0 // 执行滑出动画:菜单页面滑到左侧,原页面回到屏幕内 UIView.animate(withDuration: transitionDuration(using: transitionContext)) { fromVC.view.frame.origin.x = -container.bounds.width toVC.view.frame.origin.x = 0 } { finished in transitionContext.completeTransition(finished && !transitionContext.transitionWasCancelled) } } }
然后创建自定义导航控制器,设置代理并返回动画控制器:
class CustomNavController: UINavigationController, UINavigationControllerDelegate { override func viewDidLoad() { super.viewDidLoad() self.delegate = self } func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { // 只有pop操作时使用自定义左侧滑出动画 if operation == .pop { return LeftSlideOutTransition() } // 推入页面时可以保留你之前实现的左侧滑入动画 return nil } }
最后记得把Storyboard里的导航控制器的类改成CustomNavController,这样所有的pop操作都会使用你自定义的左侧滑出动画了。
方向3:修复Unwind Segue的动画(如果坚持用Unwind)
如果你之前尝试用Unwind Segue但没成功,可能是没正确绑定动画控制器。可以试试:
- 在主页面(汉堡菜单的父页面)定义一个Unwind动作:
@IBAction func unwindToMain(_ sender: UIStoryboardSegue) {}
- 在Storyboard里,从MenuViewController的导航栏返回按钮拖线到页面底部的"Exit"图标,选择刚才定义的
unwindToMain动作,给这个segue设置一个标识符(比如"unwindToMainSegue")。 - 在MenuViewController里实现
UIViewControllerTransitioningDelegate,返回自定义的返回动画控制器:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "unwindToMainSegue" { segue.destination.transitioningDelegate = self } } func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { return LeftSlideOutTransition() // 用刚才定义的动画类 }
这种方式相对复杂一些,适合已经大量使用Unwind Segue的场景。
内容的提问来源于stack exchange,提问作者NullHypothesis
相关产品推荐
相关产品推荐

