如何在通过导航栈推送视图控制器时实现cross dissolve动画?
实现导航栈Push时的淡入淡出(Cross Dissolve)动画
嘿,我来帮你搞定这个问题!你现在的代码里设置了modalTransitionStyle和modalPresentationStyle,但这俩是给模态跳转(比如presentViewController)用的,而你用的是pushViewController属于导航栈跳转,所以这些属性根本不会生效~ 下面给你两种可行的实现方案:
方案一:自定义导航控制器动画(推荐,可统一管理)
这种方式遵循系统的导航动画扩展规则,能方便地控制push和pop的动画,适合全局或多个页面需要相同动画的场景。
步骤1:创建自定义动画类
首先定义一个遵守UIViewControllerAnimatedTransitioning的动画类,实现淡入淡出逻辑:
class CrossDissolveTransition: NSObject, UIViewControllerAnimatedTransitioning { // 动画时长,可根据需求调整 func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.3 } // 核心动画实现 func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let toViewController = transitionContext.viewController(forKey: .to) else { return } // 将目标VC的视图添加到容器视图 transitionContext.containerView.addSubview(toViewController.view) // 初始透明度设为0 toViewController.view.alpha = 0.0 // 执行淡入动画 UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: { toViewController.view.alpha = 1.0 }) { isFinished in // 通知系统动画完成 transitionContext.completeTransition(isFinished) } } }
步骤2:设置导航控制器代理并指定动画
在你发起push的视图控制器中,遵守UINavigationControllerDelegate,并在代理方法中返回自定义的动画对象:
class YourCurrentViewController: UIViewController, UINavigationControllerDelegate { // 初始化自定义动画实例 private let crossDissolveTransition = CrossDissolveTransition() override func viewDidLoad() { super.viewDidLoad() // 设置当前VC为导航控制器的代理 navigationController?.delegate = self } // 实现代理方法,指定push时使用淡入淡出动画 func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { // 仅在push操作时使用自定义动画,pop时可返回nil用系统默认,也可以自定义pop动画 if operation == .push { return crossDissolveTransition } return nil } // 你的跳转方法 func pushToProfileVC() { guard let profileVC = storyboard?.instantiateViewController(withIdentifier: "vcProfile") else { return } navigationController?.pushViewController(profileVC, animated: true) } }
方案二:使用CATransition快速实现(轻量,适合单次跳转)
如果只是某个特定场景需要淡入淡出push,用这种方式更简单直接,不需要设置代理:
func pushToProfileVC() { guard let profileVC = storyboard?.instantiateViewController(withIdentifier: "vcProfile") else { return } // 创建淡入淡出的过渡动画 let fadeTransition = CATransition() fadeTransition.duration = 0.3 fadeTransition.type = .fade // 对应cross dissolve效果 fadeTransition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut) // 动画曲线 // 给导航控制器的视图层添加动画 navigationController?.view.layer.add(fadeTransition, forKey: kCATransition) // 注意这里要把animated设为false,避免系统默认的push动画和自定义动画冲突 navigationController?.pushViewController(profileVC, animated: false) }
两种方案对比
- 方案一:更规范,可统一管理push/pop动画,适合全局使用;缺点是需要额外创建动画类和设置代理。
- 方案二:代码量少,快速实现;缺点是如果多个页面需要使用,代码会重复,且无法统一管理pop动画(需要单独处理)。
内容的提问来源于stack exchange,提问作者Pankaj Ramchandani
相关产品推荐
相关产品推荐

