文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2023-09-04 15:41

关注

苹果又给我们挖坑了,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。

如图:

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

来源地址:https://blog.csdn.net/xuexixiaoshizhe/article/details/126955521

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯