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
相关产品推荐
相关产品推荐

