如何在不旋转前序UIViewController的情况下实现横竖屏展示与关闭
iOS竖屏应用横屏控制器返回后视图异常的解决办法
一、强制指定视图控制器永远竖屏
直接在需要保持竖屏的前序视图控制器里重写以下两个方法,让它完全不响应旋转事件:
override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait } override var shouldAutorotate: Bool { return false }
如果你的项目是iOS13及以上的SceneDelegate架构,还要在SceneDelegate里做全局旋转适配,只允许横屏控制器触发旋转:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { // 先拿到当前最上层的控制器 guard let topVC = window?.rootViewController?.topMostViewController else { return .portrait } // 如果是横屏控制器,开放左右横屏权限;否则锁死竖屏 if topVC is LandscapeViewController { return .landscapeLeft.union(.landscapeRight) } return .portrait }
这里需要给UIViewController加个扩展,用来获取当前最上层的控制器:
extension UIViewController { var topMostViewController: UIViewController { if let presentedVC = presentedViewController { return presentedVC.topMostViewController } return self } }
二、修复UITableView的布局异常
要是旋转后UITableView出现contentOffset乱跳、cell布局错位这类问题,试试这几招:
- 在前序控制器的
viewWillAppear里强制刷新布局:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) tableView.reloadData() // 重置contentOffset到顶部,避免错位 tableView.contentOffset = .zero // 强制更新约束 tableView.setNeedsLayout() tableView.layoutIfNeeded() }
- 检查UITableView的约束,别用硬编码的宽度/高度,尽量用leading、trailing这类相对superview的约束。
- 自定义cell的话,在
layoutSubviews里重新调整子视图布局,确保旋转后能自动适配:
override func layoutSubviews() { super.layoutSubviews() contentView.subviews.forEach { $0.setNeedsLayout() } }
三、更优雅的横屏展示方案
不想折腾多窗口的话,可以直接在竖屏窗口里用模态方式展示横屏控制器,靠视图变换模拟横屏效果,还支持左右旋转:
class LandscapeViewController: UIViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 根据当前设备方向调整旋转角度 let angle: CGFloat if UIDevice.current.orientation == .landscapeRight { angle = CGFloat(Double.pi/2) } else { angle = CGFloat(-Double.pi/2) } // 给视图加旋转变换 view.transform = CGAffineTransform(rotationAngle: angle) view.bounds = UIScreen.main.bounds view.center = CGPoint(x: UIScreen.main.bounds.midX, y: UIScreen.main.bounds.midY) } // 允许左右横屏旋转 override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .landscapeLeft.union(.landscapeRight) } override var shouldAutorotate: Bool { return true } }
内容的提问来源于stack exchange,提问作者Utku Eray
相关产品推荐
相关产品推荐

