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

Swift Storyboard Segue自定义滑入动画异常问题求助

问题原因

你在prepare(for:sender:)中给当前视图添加的CATransition是叠加在系统Segue默认的push动画之上的,而非替换系统动画,因此会出现先执行系统左滑动画、再执行自定义动画的冲突效果。


解决方案

下面提供两种可行的解决方式,按需选择:

方案1:手动push+自定义动画(替代Storyboard Segue)

直接放弃Segue,手动获取目标控制器并添加动画,彻底避开系统默认动画:

@IBAction func returntoLogginTapped(_ sender: Any) {
    // 从Storyboard获取目标控制器(需提前给目标VC设置Storyboard ID)
    guard let loginVC = storyboard?.instantiateViewController(withIdentifier: "LoginViewController") else { return }
    
    // 配置自定义转场动画
    let transition = CATransition()
    transition.duration = 0.3
    transition.type = .push
    transition.subtype = .fromLeft // 对应"当前VC右滑出,新VC左滑入"的效果
    transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
    
    // 给导航控制器视图层添加动画,再执行push(必须禁用系统动画)
    navigationController?.view.layer.add(transition, forKey: kCATransition)
    navigationController?.pushViewController(loginVC, animated: false)
}

注意:需要在Storyboard中给目标登录控制器设置Storyboard ID(示例中为LoginViewController),确保和代码中的标识符一致。

方案2:通过Segue实现自定义转场(保留Storyboard关联)

如果希望保留Storyboard的Segue关联,需要通过转场代理替换系统默认动画:

步骤1:让当前控制器遵循转场协议

class YourCurrentViewController: UIViewController, UINavigationControllerDelegate, UIViewControllerAnimatedTransitioning {
    // 你的现有代码...
}

步骤2:设置导航控制器代理

override func viewDidLoad() {
    super.viewDidLoad()
    navigationController?.delegate = self
}

步骤3:实现转场代理方法

// 指定转场使用自定义动画
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
    // 仅对跳转到登录页的转场生效(可通过目标VC的Restoration ID判断)
    if toVC.restorationIdentifier == "LoginViewController" {
        return self
    }
    return nil // 其他转场使用系统默认动画
}

// 自定义动画逻辑
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    let containerView = transitionContext.containerView
    guard let toVC = transitionContext.viewController(forKey: .to) else { return }
    
    // 设置目标视图初始位置(屏幕左侧外)
    toVC.view.frame = CGRect(x: -containerView.bounds.width, y: 0, width: containerView.bounds.width, height: containerView.bounds.height)
    containerView.addSubview(toVC.view)
    
    // 执行滑行动画:当前VC右滑退出,目标VC左滑进入
    UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseInOut) {
        self.view.frame = CGRect(x: containerView.bounds.width, y: 0, width: containerView.bounds.width, height: containerView.bounds.height)
        toVC.view.frame = containerView.bounds
    } completion: { _ in
        // 动画结束后恢复当前视图位置,标记转场完成
        self.view.frame = containerView.bounds
        transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
    }
}

// 设置动画时长
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
    return 0.3
}

步骤4:调整Segue相关设置

  • 无需在prepare(for:sender:)中添加任何动画代码,保留原有的performSegue调用即可。
  • 在Storyboard中给目标登录控制器设置Restoration ID(示例中为LoginViewController),确保和代码中的判断条件一致。

内容的提问来源于stack exchange,提问作者LeAnthony Howell

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 05:45:00