Xamarin.Forms iOS16强制屏幕旋转失效问题求助
解决iOS 16+ Xamarin.Forms登录页强制竖屏无效问题
问题根源
iOS 16起,Apple废弃了AppDelegate中GetSupportedInterfaceOrientations的全局调用逻辑,转而要求在ViewController层级控制屏幕方向,同时UIWindowScene的方向更新API需要更严谨的调用方式。你的代码中AppDelegate的方法不再被触发,且SetPortrait方法存在两处关键问题:
- 获取windowScene的方式不够可靠(直接取第一个ConnectedScene可能不是当前活跃场景)
- 未正确关联当前页面的ViewController来触发方向更新
修复步骤
1. 移除AppDelegate中的方向判断代码
直接删除GetSupportedInterfaceOrientations方法,后续方向控制由自定义Renderer处理。
2. 为LoginPage创建自定义PageRenderer
在iOS项目中添加LoginPage的Renderer,强制该页面仅支持竖屏:
[assembly: ExportRenderer(typeof(LoginPage), typeof(LoginPageRenderer))] namespace YourAppName.iOS.Renderers { public class LoginPageRenderer : PageRenderer { public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations() { return UIInterfaceOrientationMask.Portrait; } public override bool ShouldAutorotate() { return false; } } }
这个Renderer会在LoginPage显示时,覆盖ViewController的方向支持逻辑,确保iOS16能正确识别该页面的竖屏要求。
3. 修正SetPortrait方法的实现
更新InterfaceOrientationService.cs中的代码,确保正确获取当前活跃的windowScene,并触发方向更新:
public void SetPortrait() { if (UIDevice.CurrentDevice.CheckSystemVersion(16, 0)) { // 获取当前活跃的UIWindowScene(更可靠的方式) var windowScene = UIApplication.SharedApplication.ConnectedScenes .OfType<UIWindowScene>() .FirstOrDefault(scene => scene.ActivationState == UISceneActivationState.ForegroundActive); if (windowScene != null) { // 获取当前显示的最顶层ViewController var currentVC = UIApplication.SharedApplication.KeyWindow?.RootViewController; while (currentVC?.PresentedViewController != null) { currentVC = currentVC.PresentedViewController; } if (currentVC != null) { currentVC.SetNeedsUpdateOfSupportedInterfaceOrientations(); var preferences = new UIWindowSceneGeometryPreferencesIOS(UIInterfaceOrientationMask.Portrait); windowScene.RequestGeometryUpdate(preferences, error => { if (error != null) { Console.WriteLine($"方向更新失败: {error.LocalizedDescription}"); } }); } } } else { // iOS16以下保留原有逻辑 UIDevice.CurrentDevice.SetValueForKey(NSNumber.FromInt32((int)UIInterfaceOrientation.Portrait), new NSString("orientation")); UIApplication.SharedApplication.StatusBarOrientation = UIInterfaceOrientation.Portrait; } }
关键改进点:
- 通过
ForegroundActive状态获取当前活跃的windowScene,避免取到后台场景 - 遍历获取最顶层的PresentedViewController,确保是当前显示的页面
- 添加错误回调,方便排查更新失败的原因
4. 检查Info.plist的方向设置
确保Info.plist中允许所有方向(后续由代码动态控制):
- 在Info.plist中,找到
UISupportedInterfaceOrientations,添加以下项:- Portrait (bottom home button)
- Landscape left
- Landscape right
- 同时
UISupportedInterfaceOrientations~ipad也做相同设置(如果支持iPad)
额外注意事项
- 确保LoginPage的
OnAppearing方法中调用SetPortrait时,页面已经完成渲染(可延迟100ms调用,避免页面未加载完成导致的问题):
protected override async void OnAppearing() { base.OnAppearing(); await Task.Delay(100); DependencyService.Get<IInterfaceOrientationService>().SetPortrait(); }
- 如果使用NavigationPage,确保其他页面的Renderer正确传递方向支持逻辑(如果需要横屏)
内容的提问来源于stack exchange,提问作者Lisa Maria
相关产品推荐
相关产品推荐

