修改导航控制器返回按钮触发时的屏幕切换动画
嘿,这个需求我之前帮不少开发者搞定过,其实有几种靠谱的实现思路,我给你拆解清楚:
思路一:自定义返回按钮 + 手动添加转场动画
系统默认的返回动画是固定向右滑出,所以第一步得替换掉导航栏的默认返回按钮,自己造一个返回按钮绑定点击事件,然后在事件里手动控制页面跳转和动画:
- 先创建自定义返回按钮,比如用带箭头的
UIBarButtonItem:let backButton = UIBarButtonItem(image: UIImage(systemName: "arrow.left"), style: .plain, target: self, action: #selector(customBackAction)) navigationItem.leftBarButtonItem = backButton - 然后实现点击事件,用
CATransition添加向左滑的动画,注意要把系统默认动画关掉(animated: false):@objc func customBackAction() { let transition = CATransition() transition.duration = 0.3 // 和系统默认动画时长保持一致 transition.type = .push transition.subtype = .fromLeft // 核心:设置从左侧滑入的效果 navigationController?.view.layer.add(transition, forKey: kCATransition) // 关闭系统默认动画,避免冲突 navigationController?.popViewController(animated: false) }
这种方法适合单个页面需要自定义返回动画的场景,灵活度高。
思路二:全局设置导航控制器转场代理
如果想让整个APP的返回操作都统一用向左滑动画,那用导航控制器的代理方法更高效,不用每个页面都写一遍:
- 让你的导航控制器(或者基类控制器)遵守
UINavigationControllerDelegate协议,然后设置代理:navigationController?.delegate = self - 实现代理方法,判断是pop操作时返回自定义的动画器:
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { // 只有返回(pop)操作才用自定义动画 if operation == .pop { return CustomLeftSlideAnimator() } // push操作还是用系统默认动画 return nil } - 创建自定义动画器类,实现
UIViewControllerAnimatedTransitioning协议,编写向左滑的动画逻辑:class CustomLeftSlideAnimator: NSObject, UIViewControllerAnimatedTransitioning { // 动画时长 func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.3 } // 核心动画逻辑 func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let toVC = transitionContext.viewController(forKey: .to), let fromVC = transitionContext.viewController(forKey: .from) else { return } let container = transitionContext.containerView container.addSubview(toVC.view) // 初始状态:目标页面在屏幕左侧外面 toVC.view.frame = CGRect(x: -container.bounds.width, y: 0, width: container.bounds.width, height: container.bounds.height) UIView.animate(withDuration: transitionDuration(using: transitionContext)) { // 当前页面滑出到屏幕右侧,目标页面滑入到屏幕中间 fromVC.view.frame = CGRect(x: container.bounds.width, y: 0, width: container.bounds.width, height: container.bounds.height) toVC.view.frame = container.bounds } finished: { success in transitionContext.completeTransition(!transitionContext.transitionWasCancelled) } } }
这种方法一劳永逸,适合全局统一返回动画的场景。
思路三:Runtime Hook系统返回方法(谨慎使用)
如果你不想自定义返回按钮,也可以用Runtime的方式Hook系统的popViewController(animated:)方法,替换掉默认动画。不过这属于“黑魔法”,可能会因为iOS版本更新出现兼容性问题,只推荐在特殊场景下尝试:
- 比如通过
method_exchangeImplementations交换系统方法和自定义方法,在自定义方法里添加向左滑动画,再调用原方法(注意要关闭系统动画)。
一些注意事项
- 动画时长尽量和系统默认的0.3秒保持一致,用户体验更自然;
- 自定义返回按钮时,尽量和系统返回按钮的样式保持一致(比如箭头图标),避免用户产生困惑;
- 用代理方法时,要确保导航控制器的
delegate正确设置,避免代理失效。
内容的提问来源于stack exchange,提问作者NullHypothesis
相关产品推荐
相关产品推荐

