如何在Xcode 12中实现反向的视图控制器水平翻转转场?
实现Xcode 12中视图控制器水平翻转转场反向(左向右)的可行思路
以下是几种直接落地的解决方案,适配Xcode 12及iOS 14+环境:
方法一:自定义导航控制器转场代理
通过实现导航控制器的代理方法,替换默认的push转场动画,实现左向右的滑入效果:
// 自定义导航控制器 class CustomNavController: UINavigationController, UINavigationControllerDelegate { override func viewDidLoad() { super.viewDidLoad() delegate = self } func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { // 仅修改push操作的动画 guard operation == .push else { return nil } return ReversePushAnimator() } } // 自定义反向push动画器 class ReversePushAnimator: NSObject, UIViewControllerAnimatedTransitioning { func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.35 // 和系统默认动画时长保持一致 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let toView = transitionContext.view(forKey: .to) else { return } let container = transitionContext.containerView // 初始状态:目标视图在屏幕左侧外 toView.frame = CGRect(x: -container.bounds.width, y: 0, width: container.bounds.width, height: container.bounds.height) container.addSubview(toView) // 执行滑入动画 UIView.animate(withDuration: transitionDuration(using: transitionContext)) { toView.frame = container.bounds } finished: { success in transitionContext.completeTransition(success && !transitionContext.transitionWasCancelled) } } }
使用时,将原导航控制器替换为CustomNavController即可。
方法二:手动使用CATransition触发转场
如果只是特定场景需要反向转场,无需全局修改,可以直接在跳转前添加自定义过渡动画:
// 在跳转逻辑中添加 let targetVC = YourTargetViewController() let transition = CATransition() transition.duration = 0.35 transition.type = .push transition.subtype = .fromLeft // 指定从左向右进入 navigationController?.view.layer.add(transition, forKey: kCATransition) // 必须设置animated为false,避免系统默认动画冲突 navigationController?.pushViewController(targetVC, animated: false)
方法三:适配Modal转场(如果是模态跳转)
若需修改模态视图的转场方向,可通过设置视图控制器的转场代理实现:
// 在发起模态跳转的控制器中 class PresentingVC: UIViewController, UIViewControllerTransitioningDelegate { func presentTargetVC() { let targetVC = YourTargetViewController() targetVC.transitioningDelegate = self targetVC.modalPresentationStyle = .fullScreen present(targetVC, animated: true) } func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { return ReverseModalAnimator() } } class ReverseModalAnimator: NSObject, UIViewControllerAnimatedTransitioning { func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.35 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let toView = transitionContext.view(forKey: .to) else { return } let container = transitionContext.containerView toView.frame = CGRect(x: -container.bounds.width, y: 0, width: container.bounds.width, height: container.bounds.height) container.addSubview(toView) UIView.animate(withDuration: transitionDuration(using: transitionContext)) { toView.frame = container.bounds } finished: { success in transitionContext.completeTransition(success) } } }
注意事项
- 保持动画时长与系统默认一致(0.35秒),避免破坏用户习惯
- 若使用transform反转视图,需注意子视图的镜像问题,不推荐这种方式
- 测试时覆盖横竖屏场景,确保转场逻辑稳定
内容的提问来源于stack exchange,提问作者something
相关产品推荐
相关产品推荐

