iOS_适配 iOS16 转屏

文章介绍了在iOS16中,屏幕旋转相关API的变化,包括UIDevice的setValue方法不再支持,应改用UIWindowScene的requestGeometryUpdate方法。同时,shouldAutorotate方法的行为改变,需使用setNeedsUpdateOfSupportedInterfaceOrientations来更新屏幕方向。此外,还提到了Xcode版本差异导致的编译效果问题。
摘要由CSDN通过智能技术生成

iOS_适配 iOS16 转屏

  • 问题1:iOS 16 屏幕旋转报错:[Orientation] BUG IN CLIENT OF UIKIT: Setting UIDevice.orientation is not supported. Please use UIWindowScene.requestGeometryUpdate(_:)
    解决:iOS16 UIDevice 不再支持 setValue 方法,使用 UIWindowScenerequestGeometryUpdate() 的方法代替

  • 问题2: Xcode13Xcode14 编译出的安装包效果不一致
    解决:需要区分编译环境,写两套代码

  • 问题3:- (BOOL)shouldAutorotate{} 在iOS 16 已经不起作用了,无论返回 yes or no 都能转屏。
    解决:iOS16 新增:setNeedsUpdateOfSupportedInterfaceOrientations方法,用于通知 UIViewController 支持的屏幕方向有更新。在修改完 - (UIInterfaceOrientationMask)supportedInterfaceOrientations方法后调用

  • 问题4:iOS 16 转屏后立即获取的设备方向不正确:[UIDevice currentDevice].orientation 返回 UIDeviceOrientationUnknown
    解决:延迟回调 complete 后获取


Codes:

NSString *MODeviceOrientationDescription(UIDeviceOrientation orientation) {
    switch (orientation) {
        case UIDeviceOrientationUnknown: return @"Unknown";
        case UIDeviceOrientationPortrait: return @"Portrait";
        case UIDeviceOrientationPortraitUpsideDown: return @"PortraitUpsideDown";
        case UIDeviceOrientationLandscapeLeft: return @"LandscapeLeft";
        case UIDeviceOrientationLandscapeRight: return @"LandscapeRight";
        case UIDeviceOrientationFaceUp: return @"FaceUp";
        case UIDeviceOrientationFaceDown: return @"FaceDown";
    }
}

NSString *MOInterfaceOrientationDescription(UIInterfaceOrientation orientation) {
    switch (orientation) {
        case UIInterfaceOrientationUnknown: return @"Unknown";
        case UIInterfaceOrientationPortrait: return @"Portrait";
        case UIInterfaceOrientationPortraitUpsideDown: return @"PortraitUpsideDown";
        case UIInterfaceOrientationLandscapeLeft: return @"LandscapeLeft";
        case UIInterfaceOrientationLandscapeRight: return @"LandscapeRight";
    }
}

typedef void(^MODeviceOrientationCompletion)(NSError * _Nullable error);

void MOGeometryUpdate(UIViewController *viewController,
                      UIDeviceOrientation orientation,
                      MODeviceOrientationCompletion completion) {
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000
    /* Preprocess macro for compiling on Xcode14 */
    if (@available(iOS 16.0, *)) {
        if (![viewController respondsToSelector:@selector(setNeedsUpdateOfSupportedInterfaceOrientations)]) {
            NSString *errMsg = @"viewController can't respond setNeedsUpdateOfSupportedInterfaceOrientations";
            if (completion) {
                completion([NSError errorWithDomain:@"MODemo" code:0 userInfo:@{NSLocalizedDescriptionKey: errMsg}]);
            }
            return;
        }
        [viewController setNeedsUpdateOfSupportedInterfaceOrientations];
        [viewController.navigationController setNeedsUpdateOfSupportedInterfaceOrientations];
        
        // find scene
        NSArray<UIScene *> *scenes = [[[UIApplication sharedApplication] connectedScenes] allObjects];
        __block UIScene *firstScene = scenes.firstObject;
        [scenes enumerateObjectsUsingBlock:^(UIScene * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            // 转屏需要使用 role = UIWindowSceneSessionRoleApplication 的Scene,当取到其他Scene时,会转屏失败
            if ([obj.session.role isEqualToString:UIWindowSceneSessionRoleApplication]) {
                firstScene = obj;
                *stop = YES;
            }
        }];
        if (![firstScene isKindOfClass:[UIWindowScene class]]) {
            NSString *errMsg = [NSString stringWithFormat:@"Unexpected first scene, scenes: %@", scenes];
            if (completion) {
                completion([NSError errorWithDomain:@"MODemo" code:0 userInfo:@{NSLocalizedDescriptionKey: errMsg}]);
            }
            return;
        }
        UIWindowScene *windowScene = (UIWindowScene *)firstScene;
        UIInterfaceOrientationMask mask = 1 << orientation;
        UIWindowSceneGeometryPreferencesIOS *preferences = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:mask];
        __block NSError *err = nil;
        [windowScene requestGeometryUpdateWithPreferences:preferences errorHandler:^(NSError * _Nonnull error) {
            NSString *errMsg = [NSString stringWithFormat:@"request geometry error: %@", error];
            err = [NSError errorWithDomain:@"MODemo" code:0 userInfo:@{NSLocalizedDescriptionKey: errMsg}];
            if (completion) {
                completion(error);
            }
        }];
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            if (completion) {
                completion(err);
            }
        });
    } else {
        [[UIDevice currentDevice] setValue:@(orientation) forKey:@"orientation"];
        [UIViewController attemptRotationToDeviceOrientation];
        if (completion) {
            completion(nil);
        }
    }
#else
    /* Preprocess macro for compiling on Xcode13 */
    [[UIDevice currentDevice] setValue:@(orientation) forKey:@"orientation"];
    [UIViewController attemptRotationToDeviceOrientation];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        if (completion) {
            completion(nil);
        }
    });
#endif
}

github Demo


Reference:
Apple Developer Document
iOS 16适配屏幕旋转强制转屏切换大总结

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莫小言mo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值