如何在AppDelegate全局锁定竖屏时让单个ViewController支持横屏且不崩溃?
我之前也踩过这个坑,核心问题是全局方向控制和单个页面的方向控制逻辑冲突,尤其是iOS 13之后,苹果把窗口场景的管理从AppDelegate移到了SceneDelegate,继续用AppDelegate的老方法会干扰系统的方向判断,导致崩溃。下面给你一套稳定的实现步骤:
一、先做全局竖屏的基础设置
打开项目的Target设置,进入
General->Deployment Info,在Device Orientation里只勾选Portrait(竖屏)。这是全局方向的基础限制,避免系统默认支持其他方向。针对iOS 13+的场景管理(如果你的项目支持iOS 13及以上):
在SceneDelegate里,不需要额外写强制竖屏的代码,但如果需要确保万无一失,可以实现这个方法:func scene(_ scene: UIScene, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return .portrait }Objective-C版本:
- (UIInterfaceOrientationMask)scene:(UIScene *)scene supportedInterfaceOrientationsForWindow:(UIWindow *)window { return UIInterfaceOrientationMaskPortrait; }注意:不要在AppDelegate里实现
application:supportedInterfaceOrientationsForWindow:方法,这是导致你之前崩溃的关键——这个方法会强制全局竖屏,和单个ViewController的横屏需求冲突,让系统方向判断逻辑混乱。
二、让单个ViewController支持横屏
在需要支持横屏的ViewController里,重写以下三个方向相关的属性/方法:
Swift版本
class LandscapeAllowedVC: UIViewController { // 允许的方向:这里设置为除了倒过来的竖屏之外的所有方向,你可以根据需求改成.landscapeLeft/.landscapeRight等 override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .allButUpsideDown } // 是否允许自动旋转 override var shouldAutorotate: Bool { return true } // 页面展示时的默认方向(可选,比如你希望打开时先竖屏,再允许旋转) override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { return .portrait } }
Objective-C版本
@interface LandscapeAllowedVC : UIViewController @end @implementation LandscapeAllowedVC - (UIInterfaceOrientationMask)supportedInterfaceOrientations { return UIInterfaceOrientationMaskAllButUpsideDown; } - (BOOL)shouldAutorotate { return YES; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return UIInterfaceOrientationPortrait; } @end
三、特殊情况处理:如果是导航控制器里的页面
如果这个ViewController是被push到UINavigationController里的,需要自定义导航控制器,让它跟随当前显示页面的方向设置:
Swift版本
class CustomNavController: UINavigationController { override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return topViewController?.supportedInterfaceOrientations ?? .portrait } override var shouldAutorotate: Bool { return topViewController?.shouldAutorotate ?? false } }
Objective-C版本
@interface CustomNavController : UINavigationController @end @implementation CustomNavController - (UIInterfaceOrientationMask)supportedInterfaceOrientations { return self.topViewController.supportedInterfaceOrientations ?: UIInterfaceOrientationMaskPortrait; } - (BOOL)shouldAutorotate { return self.topViewController.shouldAutorotate ?: NO; } @end
这样导航控制器会自动根据当前显示的ViewController来判断是否允许旋转,不会和全局设置冲突。
为什么之前会崩溃?
当你在AppDelegate里强制设置全局竖屏时,系统会优先遵循这个设置,但单个ViewController又试图返回不同的方向规则,导致系统在处理方向切换时出现逻辑矛盾——比如系统认为全局只能竖屏,但页面又要求横屏,最终触发崩溃。改用项目设置+SceneDelegate(可选)做全局控制,再让单个页面重写方向方法,就能让系统的判断逻辑保持一致,避免冲突。
内容的提问来源于stack exchange,提问作者husharoonie

