Swift 4:如何在Segue转场动画完成后执行目标视图控制器代码?
嘿,我来帮你搞定这个问题!针对你用CATransition实现自定义转场后,想要在目标视图控制器(VC2)里执行代码的需求,这里有两种靠谱的方案,你可以根据现有代码情况选择:
方案一:用CAAnimation代理精准监听动画完成
这种方法不用大改你现有的代码,只需要给动画加个代理就能捕获结束时机:
- 先让你的源VC(VC1)遵循
CAAnimationDelegate协议,然后在创建转场动画时设置代理:
class ViewController1: UIViewController, CAAnimationDelegate { func goToVC2() { let transition = CATransition() transition.duration = 0.5 transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionDefault) transition.type = kCATransitionPush transition.subtype = kCATransitionFromRight transition.delegate = self // 给动画加代理 self.view.window?.layer.add(transition, forKey: nil) performSegue(withIdentifier: "你的SegueID", sender: nil) } // 动画完成时会触发这个代理方法 func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { // 先确保动画是正常完成的 guard flag else { return } // 获取已经跳转过去的VC2,调用它的自定义方法 if let vc2 = self.presentedViewController as? ViewController2 { vc2.doSomethingAfterTransition() } } }
- 然后在VC2里定义你要执行的方法:
class ViewController2: UIViewController { func doSomethingAfterTransition() { // 这里写转场完成后要执行的代码,比如更新UI、请求数据等等 print("转场完成啦,开始执行VC2的专属逻辑~") } }
方案二:改用UIKit标准自定义转场(更规范)
如果想让你的转场逻辑更贴合UIKit的设计,推荐用UIViewControllerTransitioningDelegate,这种方式扩展性更强,后续加返回动画也很方便:
- 在VC1里,手动实例化VC2并设置转场代理:
class ViewController1: UIViewController { func navigateToVC2() { guard let vc2 = storyboard?.instantiateViewController(withIdentifier: "ViewController2") as? ViewController2 else { return } vc2.transitioningDelegate = self vc2.modalPresentationStyle = .fullScreen // 根据你的需求设置展示样式 present(vc2, animated: true, completion: nil) } } // 让VC1遵循转场代理协议,提供自定义动画 extension ViewController1: UIViewControllerTransitioningDelegate { func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { return CustomPushAnimator() // 自定义动画类 } }
- 创建一个自定义动画类,实现转场动画和完成回调:
class CustomPushAnimator: NSObject, UIViewControllerAnimatedTransitioning { // 动画时长和你之前设置的一致 func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.5 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { let container = transitionContext.containerView guard let toVC = transitionContext.viewController(forKey: .to) else { return } // 把VC2的视图先放到屏幕右侧 container.addSubview(toVC.view) toVC.view.frame = container.frame.offsetBy(dx: container.frame.width, dy: 0) // 执行平移动画,模拟push效果 UIView.animate(withDuration: transitionDuration(using: transitionContext), options: .curveEaseInOut) { toVC.view.frame = container.frame } completion: { finished in // 标记转场完成,然后调用VC2的方法 transitionContext.completeTransition(finished) guard finished, let vc2 = toVC as? ViewController2 else { return } vc2.doSomethingAfterTransition() } } }
- 同样在VC2里定义
doSomethingAfterTransition方法,内容和方案一一致就行。
小提醒
尽量别用DispatchQueue.main.asyncAfter(deadline: .now() + 0.5)这种延迟执行的方式,因为动画实际完成时间可能受系统负载影响,会有误差,用代理或者标准转场的回调才是精准的做法。
内容的提问来源于stack exchange,提问作者Michael Hsu
相关产品推荐
相关产品推荐

