在做视频开发时遇到屏幕旋转问题,其中涉及到 StatusBar、 UINavigationController、UITabBarController 、UIViewcontroller

在设备锁屏下的整体效果图

主要涉及以下4点:
- 横竖屏的旋转
- 屏幕旋转相应改变视图位置
- 旋转时状态栏的隐藏与显示
- 锁屏

1、横竖屏旋转

  • 第1步:

     -(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {//    NSLog(@"0000000---------%@",NSStringFromClass([[self topViewController] class]));
    //    if ([NSStringFromClass([[self topViewController] class]) isEqualToString:@"FirstViewController"]) {//        //横屏
    //        return UIInterfaceOrientationMaskLandscapeRight;
    //    }
    //    //竖屏
    //    return UIInterfaceOrientationMaskPortrait;NSUInteger orientations = UIInterfaceOrientationMaskAllButUpsideDown;if(self.window.rootViewController){//取出当前显示的控制器UIViewController *presentedViewController = [self topViewControllerWithRootViewController:self.window.rootViewController];//按当前控制器支持的方向确定旋转方向(将旋转方向重新交给每个控制器自己控制)NSLog(@"%s, line = %d",__FUNCTION__,__LINE__);orientations = [presentedViewController supportedInterfaceOrientations];}return orientations;
    }
    //获取界面最上层的控制器
    //- (UIViewController*)topViewController {//    NSLog(@"%s, line = %d",__FUNCTION__,__LINE__);
    //    return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
    //}
    //一层一层的进行查找判断
    - (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {NSLog(@"%s, line = %d",__FUNCTION__,__LINE__);if ([rootViewController isKindOfClass:[UITabBarController class]]) {UITabBarController* tabBarController = (UITabBarController*)rootViewController;NSLog(@"Tabbar:%@",NSStringFromClass([tabBarController.selectedViewController class]));return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {UINavigationController* nav = (UINavigationController*)rootViewController;NSLog(@"nav:%@",NSStringFromClass([nav.visibleViewController class]));return [self topViewControllerWithRootViewController:nav.visibleViewController];} else if (rootViewController.presentedViewController) {NSLog(@"present:%@",NSStringFromClass([rootViewController.presentationController class]));UIViewController* presentedViewController = rootViewController.presentedViewController;return [self topViewControllerWithRootViewController:presentedViewController];} else {NSLog(@"root:%@",rootViewController);return rootViewController;}
    }
    

    代码中通过 -(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window 方法将控制器交给自己控制,该方法默认值为Info.plist中配置的Supported interface orientations项的值。

  • 第2步:在各控制器设置支持的方向

    //是否允许旋转(默认允许)
    - (BOOL)shouldAutorotate {return YES;
    }- (UIInterfaceOrientationMask)supportedInterfaceOrientations{//允许旋转的方向return UIInterfaceOrientationMaskAll;
    }

    其中- supportedInterfaceOrientations 方法在 iPad 中默认取值为 UIInterfaceOrientationMaskAll,即默认支持所有屏幕方向;而 iPhone 跟 iPod Touch 的默认取值为 UIInterfaceOrientationMaskAllButUpsideDown,即支持除竖屏向下以外的三个方向。
    在设备屏幕旋转时,系统会调用 - shouldAutorotate 方法检查当前界面是否支持旋转,只有 - shouldAutorotate返回 YES 的时候,- supportedInterfaceOrientations 方法才会被调用,以确定是否需要旋转界面。
    这个是 TabbarController 中设置的,它会影响关联的 UIViewController 的支持方向,需要在 UIViewController 中进一步设置

    //此方法来控制能否横竖屏 控制锁屏
    - (UIInterfaceOrientationMask)supportedInterfaceOrientations {NSLog(@"%s, line = %d",__FUNCTION__,__LINE__);UIInterfaceOrientationMask inter;if (_lockScreen) {switch (_lockOrientation) {case 1:inter = UIInterfaceOrientationMaskPortrait;break;case 2:inter = UIInterfaceOrientationMaskPortraitUpsideDown;break;case 3:inter = UIInterfaceOrientationMaskLandscapeRight;break;case 4:inter = UIInterfaceOrientationMaskLandscapeLeft;break;default:inter = UIInterfaceOrientationMaskAll;break;}} else {inter = UIInterfaceOrientationMaskAll;}//支持全部方向return inter;
    }
  • 第3步:强制转换控制器方向

    - (void)setInterOrientation:(UIInterfaceOrientation)orientation {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                  = orientation;// 从2开始是因为0 1 两个参数已经被selector和target占用[invocation setArgument:&val atIndex:2];[invocation invoke];}
    }

    这样就可以完成横竖屏的切换。

2、屏幕旋转相应改变视图位置

这里先扩展UIDeviceOrientation & UIInterfaceOrientation的知识

  • UIDeviceOrientation 设备的物理方向
    UIDeviceOrientation即我们手持的移动设备的Orientation,是一个三围空间,有六个方向,通过[UIDevice currentDevice].orientation获取当前设备的方向。

    typedef NS_ENUM(NSInteger, UIDeviceOrientation) {UIDeviceOrientationUnknown,UIDeviceOrientationPortrait,            UIDeviceOrientationPortraitUpsideDown,  // Device oriented vertically, home button on the top 竖屏向下,即头在下,Home 键在上UIDeviceOrientationLandscapeLeft,       // Device oriented horizontally, home button on the right 横屏头在左,Home键在右UIDeviceOrientationLandscapeRight,      // Device oriented horizontally, home button on the left  横屏头在右,Home键在左UIDeviceOrientationFaceUp,              // Device oriented flat, face upUIDeviceOrientationFaceDown             // Device oriented flat, face down
    } ;
  • UIInterfaceOrientation界面的显示方向

    UIInterfaceOrientation即我们看到的视图的Orientation,可以理解为statusBar所在的方向,是一个二维空间,有四个方向, 通过[UIApplication sharedApplication].statusBarOrientation即状态栏的方向获取当前界面方向。

    // Note that UIInterfaceOrientationLandscapeLeft is equal to   UIDeviceOrientationLandscapeRight (and vice versa).
    // This is because rotating the device to the left requires rotating the content to the right.
    typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {UIInterfaceOrientationUnknown            = UIDeviceOrientationUnknown,UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait,UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight,UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft
    } 
  • UIInterfaceOrientationMask支持的方向

    // iOS 6 之后用于控制界面的枚举值
    typedef NS_OPTIONS(NSUInteger, UIInterfaceOrientationMask) {
    UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait),
    UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft),
    UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight),
    UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown),
    UIInterfaceOrientationMaskLandscape = (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
    UIInterfaceOrientationMaskAll = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown),
    UIInterfaceOrientationMaskAllButUpsideDown = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight),
    }

    由上可以发现:

    1. iOS 6 及之后版本使用的UIInterfaceOrientationMask类型来控制屏幕屏幕方向,该类型也新增加了几个枚举取值,可用一个枚举取值来代表多个屏幕方向,使用起来更方便。
    2. 注意在UIInterfaceOrientation中有注释 Note that UIInterfaceOrientationLandscapeLeft is equal to UIDeviceOrientationLandscapeRight (and vice versa).
      This is because rotating the device to the left requires rotating the content to the right ,大意是界面的左转相当于设备的右转,如果设备向左转时就需要内容(即界面)向右转。即:
      UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight
      UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft
      下面还会举例说明。

其实UIDeviceOrientationUIInterfaceOrientation是两个互不相干的属性,通常情况下会一起出现,在这里正好利用此特性在屏幕旋转后进行重新布局。

4、锁屏

锁屏时,不管系统锁屏是否关闭、Push 或 Present 返回后,界面依然保持不变。

  • 第1步:监听 UIDeviceOrientationDidChangeNotification状态

    //监听设备旋转 改变 视图 对应位置
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange) name:UIDeviceOrientationDidChangeNotification object:nil];//用来控制横竖屏时调整视图位置
    - (void)deviceOrientationDidChange
    {[self isPortrait];
    }
  • 第2步:重新布局

    if (_interOrientation == UIInterfaceOrientationPortrait || _interOrientation == UIInterfaceOrientationPortraitUpsideDown) {self.top.constant = 145;self.bottom.constant = 210;} else if (_interOrientation == UIInterfaceOrientationLandscapeRight || _interOrientation == UIInterfaceOrientationLandscapeLeft) {self.top.constant = 40;self.bottom.constant = 50;}

    例如:竖屏转横屏
    界面竖屏UIInterfaceOrientationPortrait ->横屏UIInterfaceOrientationLandscapeRight,设备方向UIDeviceOrientationPortrait->UIDeviceOrientationLandscapeLeft,在设备发生变化这个过程触发UIDeviceOrientationDidChangeNotification监听,然后进行重新布局。

3、旋转时状态栏的隐藏与显示

  • 这里只记述旋转时状态栏的变化,由竖屏想横屏变化时状态栏会消失。

    //在需要的`UIViewController`设置是否隐藏
    - (BOOL)prefersStatusBarHidden {
    NSLog(@"%s, line = %d",__FUNCTION__,__LINE__);
    return NO;
    }

4、锁屏

锁屏时,不管系统锁屏是否关闭、Push 或 Present 返回后,界面依然保持不变。

  • 第1步:设置锁屏

    - (IBAction)lockAction:(UIButton *)sender {if (_lockScreen) {_lockScreen = NO;[sender setTitle:@"锁定屏幕" forState:UIControlStateNormal];} else {_lockScreen = YES;[sender setTitle:@"解开屏幕" forState:UIControlStateNormal];}_lockOrientation = _interOrientation;
    }
  • 第2步:绕过强转

    - (void)interfaceOrientation:(UIInterfaceOrientation)orientation
    {[self isPortrait];//锁屏情况下 不旋转if (!_lockScreen) {[self setInterOrientation:orientation];}
  • 第3步:针对 Push 或 Present 返回后

    - (void)viewWillAppear:(BOOL)animated {if (_lockScreen) {//记录返回时的界面状态[self setInterOrientation:_lockOrientation];} else {[self isPortrait];}
    }

5、 针对特定UIViewController方向的支持

-(UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {if ([NSStringFromClass([[self topViewController] class]) isEqualToString:@"FirstViewController"]) {//横屏return UIInterfaceOrientationMaskLandscapeRight;}//竖屏return UIInterfaceOrientationMaskPortrait;}

最后的献上GitHub代码,还有2个小的 bug ,有兴趣的朋友欢迎来探讨。

- 参考文章:

iOS 屏幕旋转问题总结
iOS 屏幕方向那点事儿

iOS屏幕旋转与锁屏相关推荐

  1. iOS开发屏幕旋转锁定横竖屏解决方法

    iOS开发屏幕旋转锁定横竖屏解决方法 使用场景: 公司最近产品,有两个界面是横屏的,其他的界面是竖屏的.针对这个需求,也调试了一段时间.在网上也查找了不少资料. 解决的方案也是有的,但是都是需要在导航 ...

  2. ios开发之MPNowPlayingInfoCenter 锁屏显示正在播放的音乐

    今天在床上玩唱吧,听着歌锁屏了,当点亮屏幕的时候,锁屏页面出现了我正在听得歌曲 壁纸也换成了唱吧里面的歌手图片.做ios好几年了,从没有做过这个需求 于是好奇就翻看ios的API文档找到了这个类. 如 ...

  3. iOS 屏幕旋转问题总结

    1.两个Orientation 1.1设备的物理方向(UIDeviceOrientation) typedef NS_ENUM(NSInteger, UIDeviceOrientation) {UID ...

  4. ios屏幕旋转学习笔记

    加速计是整个IOS屏幕旋转的基础,依赖加速计,设备才可以判断出当前的设备方向,IOS系统共定义了以下七种设备方向: typedef NS_ENUM(NSInteger, UIDeviceOrienta ...

  5. CentOS系统里如何正确取消或者延长屏幕保护自动锁屏功能(图文详解)

    不多说,直接上干货! 对于我这里想说的是,分别从CentOS6.X  和  CentOS7.X来谈及. 1. 问题:默认启动屏幕保护 问题描述: CentOS系统在用户闲置一段时间(默认为5分钟)后, ...

  6. Android关闭屏幕时不锁屏

    Android关闭屏幕时不锁屏 权限 <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/ ...

  7. 慎重升级!iOS 13可绕过锁屏密码查看通讯录、照片、短信

    自从,上个星期 iPhone 11 发布之后,我已经好几天没睡好觉了.转发了好多抽奖微博,第六感告诉我,这次我怎么也能欧气一回. 反正不欧气也关系,毕竟只要一个肾,我打算自己买一个. 听说我要买手机的 ...

  8. iOS屏幕旋转 浅析

    一.两种orientation 了解屏幕旋转首先需要区分两种orientation 1.device orientation 设备的物理方向,由类型UIDeviceOrientation表示,当前设备 ...

  9. iOS屏幕旋转及其基本适配方法

    屏幕旋转示例.jpeg 前段时间抽空总结了一下iOS视频播放的基本用法,发现这其中还有一个我们无法绕过的问题,那就是播放界面的旋转与适配.的确,视频播放与游戏类型的App经常会遇到这个的问题.由于至今 ...

  10. 一键清除苹果锁屏密码_极品苹果手机解锁软件ios解锁大师苹果手机锁屏密码忘了不用愁...

    苹果手机因其得天独厚操作系统的优势使得即便安卓系统发展到现在的版本以及硬件存储参数达到了惊人的8GB/128GB.10GB/256GB依然没有完全撼动苹果IOS系统的霸主地位,所以苹果Iphone手机 ...

最新文章

  1. C# 托管资源和非托管资源
  2. Redis 集群分布式锁与 API 网关分布式限流
  3. 图像处理——基于OpenCV的canny边缘检测
  4. JSONObject 和 GSON 解析 JSON 数据详解(转)
  5. 《Unit Testing》2.1 伦敦学派如何做隔离
  6. 【tool】kali连接rdp远程桌面
  7. Required String parameter 'images' is not present
  8. Spark 自己实现分箱逻辑遇到的坑
  9. 本博文记录需要解决的问题
  10. Spring学习手札(二)面向切面编程AOP
  11. IOS技术分享| 你画我猜小游戏快速实现
  12. Docker容器监控cAdvisor
  13. C语言二刷第七天:字符串(mooc视频;老师:翁恺)
  14. 从成人网站年终数据统计看各操作系统的份额表现
  15. vue + Element UI 动态Breadcrumb 面包屑的制作
  16. CAD/CAM 软件架构总结
  17. 分布式系统实践学习总结
  18. AudioRecord
  19. 请更换备份电池 pos机_UPS电池维护与保养
  20. Pytorch移植Deeplabv3训练CityScapes数据集详细步骤

热门文章

  1. 锂电池欧姆内阻和极化内阻
  2. html+css制作小米商城官网初尝试
  3. html怎样改成png格式,如何将jpg图片转换成png格式 又怎样把png转换成jpg
  4. Navicat Premium 连接 MongoDB 失败: Cannot connect to MongoDB.No suitable servers found: ......
  5. RCC_APB2Periph_AFIO的理解。。。重映射的一点心得
  6. Hi3519内核配置uart串口
  7. 程序员眼中的中国传统文化-王阳明《传习录》21
  8. 怎么在国内创建谷歌账号_如何在Google文档中创建模板
  9. Google测试之道读后感
  10. 剩余方差matlab,matlab 统计基本函数 var方差