使用自定义转场时,如何解决根视图控制器旋转后视图帧未更新问题?
解决自定义转场后根视图控制器Frame未更新的问题
这个问题我之前在做自定义转场的时候也踩过坑!本质是自定义转场会绕过系统默认的视图布局更新逻辑,尤其是在旋转后,根VC的视图没有收到重新布局的通知。下面给你几个靠谱的解决办法,都能保留自定义转场的同时修复这个问题:
1. 在转场动画完成时手动触发根VC的布局更新
这是最直接的临时修复方案,适合快速验证问题。在自定义转场动画的完成回调里,主动让根VC的视图重新计算布局:
class CustomPresentAnimator: NSObject, UIViewControllerAnimatedTransitioning { func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.3 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let toVC = transitionContext.viewController(forKey: .to), let fromVC = transitionContext.viewController(forKey: .from) else { transitionContext.completeTransition(false) return } // 你的自定义转场动画逻辑... let containerView = transitionContext.containerView containerView.addSubview(toVC.view) toVC.view.frame = CGRect(x: containerView.bounds.width, y: 0, width: containerView.bounds.width, height: containerView.bounds.height) UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: { toVC.view.frame = containerView.bounds fromVC.view.alpha = 0.8 }) { finished in fromVC.view.alpha = 1.0 transitionContext.completeTransition(finished) // 关键:触发根VC的布局更新 if let rootVC = UIApplication.shared.keyWindow?.rootViewController { rootVC.view.setNeedsLayout() rootVC.view.layoutIfNeeded() } } } }
原理:转场完成后,强制根VC的视图重新执行布局流程,确保frame适配当前屏幕方向。
2. 自定义PresentationController规范处理布局
这是更优雅的长期解决方案,从转场的根源修复问题。系统默认的present转场会通过PresentationController管理视图的布局和旋转适配,自定义转场时我们需要自己实现这个逻辑:
第一步:创建自定义PresentationController
class CustomPresentationController: UIPresentationController { // 确保presented视图全屏展示,让系统正确处理旋转后的布局 override var shouldPresentInFullscreen: Bool { return true } // 容器视图布局时,同步更新presented视图的frame override func containerViewWillLayoutSubviews() { super.containerViewWillLayoutSubviews() presentedView?.frame = containerView?.bounds ?? .zero } // 旋转后通知根VC更新布局 override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) coordinator.animate(alongsideTransition: { _ in self.presentedView?.frame = self.containerView?.bounds ?? .zero }, completion: { _ in if let rootVC = self.presentingViewController { rootVC.view.setNeedsLayout() rootVC.view.layoutIfNeeded() } }) } }
第二步:在根VC中返回自定义PresentationController
class RootViewController: UIViewController { override func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { return CustomPresentationController(presentedViewController: presented, presenting: presenting) } // 其他代码... }
原理:通过自定义PresentationController,让系统的旋转和布局逻辑正常参与转场流程,避免布局更新被遗漏。
3. 在子VC消失时主动触发根VC布局
如果上面的方案不适用,也可以在子VC即将消失时,主动通知根VC更新布局:
class ChildViewController: UIViewController { override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // 确保回到根VC时触发布局 if let rootVC = presentingViewController as? RootViewController { rootVC.view.setNeedsLayout() rootVC.view.layoutIfNeeded() } } }
这个方案适合简单场景,但不如第二种方案规范,因为它把布局逻辑耦合到了子VC中。
内容的提问来源于stack exchange,提问作者rawbee
相关产品推荐
相关产品推荐

