zoukankan      html  css  js  c++  java
  • 【精】iOS6 及其以上版本号自己主动旋转、手动强制旋转方案及布局适配

    1、布局适配方式

    本文不讨论哪种布局适配方式最好。此处使用的是 Masonry 纯代码布局适配。

    (Masonry 底层就是 AutoLayout 的 NSLayoutConstraint)

    2、iOS 方向枚举类

    // 三维设备方向
    typedef NS_ENUM(NSInteger, UIDeviceOrientation) {
        UIDeviceOrientationUnknown,
        UIDeviceOrientationPortrait,            // Device oriented vertically, home button on the bottom
        UIDeviceOrientationPortraitUpsideDown,  // Device oriented vertically, home button on the top
        UIDeviceOrientationLandscapeLeft,       // Device oriented horizontally, home button on the right
        UIDeviceOrientationLandscapeRight,      // Device oriented horizontally, home button on the left
        UIDeviceOrientationFaceUp,              // Device oriented flat, face up
        UIDeviceOrientationFaceDown             // Device oriented flat, face down
    };
    
    // 二维界面方向
    typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
        UIInterfaceOrientationUnknown            = UIDeviceOrientationUnknown,
        UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait,
        UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
        UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight,
        UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft
    };
    
    // iOS6 以后引入组合方式
    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),
    };
    获取设备方向:[[UIDevice currentDevice] orientation]
    获取界面方向:[[UIApplication sharedApplication] statusBarOrientation]

    3、iOS6 及其以上版本号页面旋转设置方法

    // 返回是否支持屏幕旋转
    - (BOOL)shouldAutorotate
    {
        return YES;  
    }
    
    // 返回支持的旋转方向
    - (NSUInteger)supportedInterfaceOrientations  
    {  
        return UIInterfaceOrientationMaskAll;  
    }
    
    // 返回优先显示的屏幕方向,假设不设置,默认与进入前一个页面保持一致(注意该方法仅仅对 ModalViewController 有效)
    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
    {  
        return UIInterfaceOrientationLandscapeLeft;  
    }

    4、影响界面旋转特性的层级因素

    (1)针对全局
    Info.plist 文件里 Supported interface orientations 支持的方向。
    (2)针对 Window
    AppDelegate 中 supportedInterfaceOrientationsForWindow 支持的方向。
    (3)针对单个页面
    假设是 ChildrenViewController,则受限于其 RootViewController 中 shouldAutorotate 和 supportedInterfaceOrientations 支持的方向。(RootViewController 指 self.window.rootViewController 设置的那个 ViewController)
    假设是 ModalViewController,则受限于其自身 shouldAutorotate 和 supportedInterfaceOrientations 支持的方向。(假设 ModalViewController 是经过包装的还有一个 RootViewController,则与上述 ChildrenViewController 原理类似)
    注意:上述三个层级因素终于的交集即为子视图控制器支持的旋转方向,假设交集为空。则会抛 UIApplicationInvalidInterfaceOrientationException 异常。

    5、屏幕旋转机制流程

    (1)加速计检測到方向变化。发出 UIDeviceOrientationDidChangeNotification 通知。
    (2)程序接收到通知,通过 AppDelegate 知会当前程序的 Window。
    (3)Window 通知 RootViewController。依据下面设置决定是否旋转。

    • Info.plist 中 Supported interface orientations 是否支持该方向
    • AppDelegate 中 supportedInterfaceOrientationsForWindow 中是否支持该方向
    • RootViewController 中 shouldAutorotate 是否为 YES
    • RootViewController 中 supportedInterfaceOrientations 是否支持该方向
    (4)RootViewController 通知其 ChildrenViewController,同步旋转操作。


    普通情况下 ChildrenViewController 不单独设置。与 RootViewController 保持一致。假设特殊场景须要单独设置,能够通过在 RootViewController 中下放权限。如:NavigationController 能够通过 self.topViewController 下放权限;TabBarController 能够通过 self.selectedViewController 下放权限。可是要注意,即使下放了权限,ChildrenViewController 还是必须遵守 Info.plist 和 AppDelegate 中的设置。
    (5)假设存在弹出的 ModalViewController,则不受限于步骤4中的 RootViewController,仅仅依据 Info.plist、AppDelegate 及其自身所支持的旋转设置决定是否旋转。假设 ModalViewController 是经过包装的还有一个 RootViewController。则与步骤4原理类似。

    6、产品开发中的应对策略。

    (1)应用仅仅须要支持单一方向。

    在 Info.plist 中锁死指定方向。限制屏幕旋转。
    (2)应用统一支持多个方向自己主动旋转。在 Info.plist 中设置应用支持的方向,每一个页面进行对应的自己主动旋转布局适配。


    (3)应用不同页面支持的方向不一致。在 Info.plist 中设置全部页面支持的方向的并集。在 RootViewController 中将权限下放,由页面但与控制自己的旋转设置。


    7、实际场景应用(有演示样例 Demo)

    注意:本文不考虑 iOS6 下面版本号的兼容性。所下面述 demo 仅仅适配 iOS6 及其以上版本号(仅仅在 iOS7、iOS8 測试过)。下述场景处理方案中,iPad 默认支持四个方向,iPhone 默认支持 UIInterfaceOrientationMaskPortraitUpsideDown 三个方向。
    (1)应用场景1:应用支持单一方向,限制旋转。(iPhone 中一般此方式用得比較多)
    思路:在 Info.plist 中锁死指定方向,其它旋转设置均不用配置。适配方式比較多,也比較easy,只是建议纯代码的话还是通过 Masonry 进行布局适配。
    演示样例:LimitPortraitDemo
    (2)应用场景2:应用统一支持多方向自己主动旋转。(iPad 中一般此方式用得比較多)
    思路:在 Info.plist 中设置应用支持的旋转方向就可以。其它旋转设置均不用配置。布局要分别适配横屏与竖屏,纯代码的话建议通过 Masonry 进行布局适配。
    演示样例:AnyRotationDemo
    (3)应用场景3:应用支持单一方向。可是个别页面支持自己主动旋转。(一般不建议使用,除非特定场景,如视频播放器页面,自己主动旋转后横屏观看效果更好)
    思路:在 Info.plist 中设置应用支持的全部旋转方向。在 RootViewController 中通过 shouldAutorotate 和 supportedInterfaceOrientations 锁死指定方向。然后在 ModalViewController 中通过 shouldAutorotate 和 supportedInterfaceOrientations 设置多个旋转方向。并进行对应的布局适配。

    适配方式纯代码的话相同建议 Masonry。
    演示样例:SingleRotationDemo
    (4)应用场景4:应用支持单一方向,可是个别页面支持手动控制旋转。不支持自己主动旋转。(一般不建议使用,除非特定场景。如视频播放器页面限制自己主动旋转,点击全屏button后横屏观看)
    思路:有两种强制方式旋转方式,一种是带导航栏的,一种是不带导航栏的。具体实现思路演示样例中有具体描写叙述。
    演示样例:ForceRotationDemo

    8、相关注意事项

    • 一般都不建议在程序里面直接调用 UIDeviceOrientation 的方向,而是用 UIInterfaceOrientation。

    • 获取屏幕方法,不要使用[[UIDevice curentDevice] orientation],建议使用[[UIApplication sharedApplication] statusBarOrientation]。
    • 假设 shouldAutorotate 返回 YES 的话,设置 setStatusBarOrientation 是无论用的。
    • 假设 shouldAutorotate 返回 NO 的话,[[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)] 方法是无论用的。
    • 尽量不要使用强制旋转的方式。通过 present 出 ModalViewController 方式。单独控制每一个试图控制器的旋转设置。

      苹果官方也是支持这样的方式。

  • 相关阅读:
    【转】WPF DataGridComboBoxColumn使用
    【转】CAD 二次开发--属性块 Block和BlockReference
    【转】【Revit】Revit二次开发——读取cad中的文字信息
    【转】【Centos】Linux(Centos7)下搭建SVN服务器
    现代php编程
    drone实践记录
    PHP拆分YAPI导出的swagjson文件
    pydantic验证器Validator
    利用notion打造读书追逐系统
    opencv马赛克python实现
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/7308577.html
Copyright © 2011-2022 走看看