You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在通过导航栈推送视图控制器时实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:02:38