iOS 16适配屏幕旋转强制转屏切换大总结

news/2024/11/17 3:31:28/

问题原因:

苹果又给我们挖坑了,iOS 16屏幕旋转报错:[Orientation] BUG IN CLIENT OF UIKIT: Setting UIDevice.orientation is not supported. Please use UIWindowScene.requestGeometryUpdate(_:)

坑:听说xcode 14 和 xcode 13编译出的安装包效果不一,经测试确实如此!还是要打包测试完毕以后再上线哦!

解决办法:

坑1、

经过实验,以前的方法直接给UIDevice  setOrientation: 的方式还是生效的,只不过需要适配一下。

首先我们应该注意到iOS 16新增加了一个方法:setNeedsUpdateOfSupportedInterfaceOrientations

/// Notifies the view controller that a change occurred that affects supported interface orientations or the preferred interface orientation for presentation.
/// By default, this will animate any changes to orientation. To perform a non-animated update, call within `[UIView performWithoutAnimation:]`.
- (void)setNeedsUpdateOfSupportedInterfaceOrientations API_AVAILABLE(ios(16.0));

这和更新状态栏的方法有点像,简单点说就是你想转屏可以,需要通知UIViewController 你已经准备好要转屏的方向了,然后再调用转屏方法即可(转屏方法后面会讲到)。

坑2、

调用完转屏方法以后,view需要重新更新frame,这时候你会发现获取到的屏幕宽高并不是你要转屏以后的结果。难道是在iOS 16中转屏不及时更新UIScreen的size了? 可能是吧!这里我们就需要自己判断一下到底需要什么样的宽度和高度啦!

坑3、

据我实验 - (BOOL)shouldAutorotate{} 在iOS 16中不再起效果!不管返回YES还是NO都能转屏!!!反而是需要控制- (UIInterfaceOrientationMask)supportedInterfaceOrientations有效果,神奇不!!

坑4、

据我实验在iOS 16中转屏的时候,直接获取设备方向:

UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;

将返回UIDeviceOrientationUnknown,是不是神坑!!!!!

转屏方法总结:

iOS 16以前的写法:如果你还在用Xcode13,且配合使用setNeedsUpdateOfSupportedInterfaceOrientations,此方案编译的包在iOS 16上依然有效!

if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {SEL selector = NSSelectorFromString(@"setOrientation:");NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];[invocation setSelector:selector];[invocation setTarget:[UIDevice currentDevice]];int val = UIDeviceOrientationPortrait;[invocation setArgument:&val atIndex:2];[invocation invoke];
}
[UIViewController attemptRotationToDeviceOrientation];

当然,据实验所知,iOS 16以后也能用,只不过会有日志警告。如果你用Xcode 14 ,此方案在iOS 16上就不好用了!

iOS 16的写法:建议升级Xcode 14

if (@available(iOS 16.0, *)) {// setNeedsUpdateOfSupportedInterfaceOrientations 方法是 UIViewController 的方法[self setNeedsUpdateOfSupportedInterfaceOrientations];NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];UIWindowScene *scene = [array firstObject];// 屏幕方向UIInterfaceOrientationMask orientation = isLaunchScreen ? UIInterfaceOrientationMaskLandscape: UIInterfaceOrientationMaskPortrait;UIWindowSceneGeometryPreferencesIOS *geometryPreferencesIOS = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:orientation];// 开始切换[scene requestGeometryUpdateWithPreferences:geometryPreferencesIOS errorHandler:^(NSError * _Nonnull error) {NSLog(@"错误:%@", error);}];
}

当然如果你没有升级到Xcode 14,还可以这样写:(据我实验不好用,只能横屏,不能再转到竖屏,不推荐此方案!)

if (@available(iOS 16.0, *)) {void (^errorHandler)(NSError *error) = ^(NSError *error) {NSLog(@"错误:%@", error);};
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"SEL supportedInterfaceSelector = NSSelectorFromString(@"setNeedsUpdateOfSupportedInterfaceOrientations");[self performSelector:supportedInterfaceSelector];NSArray *array = [[UIApplication sharedApplication].connectedScenes allObjects];UIWindowScene *scene = (UIWindowScene *)[array firstObject];Class UIWindowSceneGeometryPreferencesIOS = NSClassFromString(@"UIWindowSceneGeometryPreferencesIOS");if (UIWindowSceneGeometryPreferencesIOS) {SEL initWithInterfaceOrientationsSelector = NSSelectorFromString(@"initWithInterfaceOrientations:");UIInterfaceOrientationMask orientation = UIInterfaceOrientationMaskPortrait;id geometryPreferences = [[UIWindowSceneGeometryPreferencesIOS alloc] performSelector:initWithInterfaceOrientationsSelector withObject:@(orientation)];if (geometryPreferences) {SEL requestGeometryUpdateWithPreferencesSelector = NSSelectorFromString(@"requestGeometryUpdateWithPreferences:errorHandler:");if ([scene respondsToSelector:requestGeometryUpdateWithPreferencesSelector]) {[scene performSelector:requestGeometryUpdateWithPreferencesSelector withObject:geometryPreferences withObject:errorHandler];}}}
#pragma clang diagnostic pop
}

另外一个需求:如果你的页面不需要自动转屏,只需要点击按钮触发转屏。你还可以这样写:

横屏按钮点击事件:

if (@available(iOS 16, *)) {_landscape = YES;[self setNeedsUpdateOfSupportedInterfaceOrientations];
}

竖屏按钮点击事件:

if (@available(iOS 16, *)) {_landscape = NO;[self setNeedsUpdateOfSupportedInterfaceOrientations];
}

再加一个方法:

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {if (_landscape){//横屏return UIInterfaceOrientationMaskLandscape;}else{//竖屏return UIInterfaceOrientationMaskPortrait;}
}

极简单的代码即可完成你想要的效果。

注意事项:

如果你的[self setNeedsUpdateOfSupportedInterfaceOrientations] 没起任何作用,你可以需要在主线程main queue中调用它!

总结完毕!有疑问欢迎下方留言讨论!

HXRotationTool更新:iOS 屏幕旋转工具类,兼容iOS 16,兼容Xcode 13和Xcode 14。

GitHub - TheLittleBoy/HXRotationTool: iOS 屏幕旋转工具类,兼容iOS 16,兼容Xcode 13和Xcode 14。

如图:

喜欢的小伙伴就帮忙点个收藏吧~ 


http://www.ppmy.cn/news/734885.html

相关文章

快捷键实现MAC或者WINDOWS下快速切换显示器输入源

目录 通过键盘实现mac或者Windows显示器输入信号源快捷键切换(电脑怎么切换屏幕的信号输入) 前言一、通过显示器菜单按钮控制二、通过快捷键设置1.window系统对ControlMyMonitor做一点补充(不想对软件有详细了解的可直接跳过,不…

【专升本-英语单词】500-1000需复习词汇

单词翻译affection forphr. - 对…的感情。ahead of timephr. - 提前,提早。neglectv. - 忽视。objectiven. - 目标,目的;adj. - 客观的。all butphr. - 除…以外的所有。all overphr. - 到处,普及。requirev. - 规定。previousad…

漏洞复现 || 畅捷通T+ net反序列化

免责声明 技术文章仅供参考,任何个人和组织使用网络应当遵守宪法法律,遵守公共秩序,尊重社会公德,不得利用网络从事危害国家安全、荣誉和利益,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此…

忍者的时代用计算机怎么弹,火影忍者百豪纲手怎么玩 上墙 弹墙 三连摔操作方法...

火影忍者2020年5月限定忍者百豪纲手已经正式上线,这是当前版本中首位可以上墙的角色,即使没有进行攻击也可以跳到空中躲技能或者攻击,同时还有特殊的三连摔机制,不过很多玩家还不清楚百豪纲手该怎么玩,下面趣趣手游网小…

GENMARK控制器维修S08S4P.D工业电脑维修

机器人GENMARK SYSTEM CONTROLLER系统控制器维修S08S4P.D工业电脑;晶圆转移机器人SΛΛALL CONTROLLER; SΛΛC1100 半导体设备机械臂GENMARK控制器等 GenMark的两大构架:eSensor(电子传感)和Elecitrowetting&#xf…

【运维】迁移Git项目到新的地址

【运维】迁移Git项目到新的地址 包含所有分支 及其提交记录等 迁移项目 1 创建新的空项目 newProject https://127.0.0.1/new/newProject.git 2 克隆老项目 git clone --mirror https://127.0.0.2/old/oldProject.git 进入老项目目录 cd oldProject 3将老项目更改远程地址…

docker上安装es

安装docker 1 安装docker依赖 yum install -y yum-utils2 设置docker仓库镜像地址 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo3 安装制定版本的docker yum -y install docker-ce-20.10.17-3.el74 查看是否安装成功 y…

使用notability时 iPad pro屏幕中间发热

使用notability时 iPad pro屏幕中间发热,耗电异常。这是由于某一版的notability有bug,解决办法就是在设置里面滑到notability软件的设置里面,打开安全模式既可解决耗电问题。