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 中锁死指定方向,其他旋转设置均不用配置,适配方式比较多,也比较容易,不过建议纯代码的话还是通过 Masonry 进行布局适配。

示例:LimitPortraitDemo

(2)应用场景2:应用统一支持多方向自动旋转。(iPad 中一般此方式用得比较多)

思路:在 Info.plist 中设置应用支持的旋转方向即可,其他旋转设置均不用配置,布局要分别适配横屏与竖屏,纯代码的话建议通过 Masonry 进行布局适配。

示例:AnyRotationDemo

(3)应用场景3:应用支持单一方向,但是个别页面支持自动旋转。(一般不建议使用,除非特定场景,如视频播放器页面,自动旋转后横屏观看效果更好)

思路:在 Info.plist 中设置应用支持的所有旋转方向,在 RootViewController 中通过 shouldAutorotate 和 supportedInterfaceOrientations 锁死指定方向,然后在 ModalViewController 中通过 shouldAutorotate 和 supportedInterfaceOrientations 设置多个旋转方向,并进行相应的布局适配。适配方式纯代码的话同样建议 Masonry。

示例:SingleRotationDemo

(4)应用场景4:应用支持单一方向,但是个别页面支持手动控制旋转,不支持自动旋转。(一般不建议使用,除非特定场景,如视频播放器页面限制自动旋转,点击全屏按钮后横屏观看)

思路:有两种强制方式旋转方式,一种是带导航栏的,一种是不带导航栏的。具体实现思路示例中有详细描述。

示例:ForceRotationDemo

8、相关注意事项

  • 一般都不建议在程序里面直接调用 UIDeviceOrientation 的方向,而是用 UIInterfaceOrientation。
  • 获取屏幕方法,不要使用[[UIDevice curentDevice] orientation],建议使用[[UIApplication sharedApplication] statusBarOrientation]。
  • 如果 shouldAutorotate 返回 YES 的话,设置 setStatusBarOrientation 是不管用的。
  • 如果 shouldAutorotate 返回 NO 的话,[[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)] 方法是不管用的。
  • 尽量不要使用强制旋转的方式,通过 present 出 ModalViewController 方式,单独控制每个试图控制器的旋转设置。苹果官方也是支持这种方式。

版权声明:本文为博主原创文章,转载请声明出处:http://blog.csdn.net/jinnchang

时间: 2024-12-19 02:45:27

iOS6 及其以上版本自动旋转、手动强制旋转方案及布局适配的相关文章

JavaScript 图片广告自动与手动的切换

?1.代码 <html> <head>   <script type="text/javascript" src="jquery-1.8.js"></script>   <script type="text/javascript" src="pictrue-con.js"></script>   <style>            #pic1

app版本自动更新-iOS忙里偷闲整理系列

原理啊,其实很简单,就是比较app的当前版本号和服务器上的版本号是否一样,不一样就提示更新. iOS程序自动提示更新的实现方案大致分为两种:第一种,自己服务器提供一个接口,告知相关app的当前版本,是否需要更新,以及更新的地址等信息 .第二种,就是利用苹果的appStore 提供的相关api进行查询更新. 代码如下: #define APPUrl @"http://itunes.apple.com/lookup?id=你应用ID 在itunes上的" // 检查是否更新 -(void)

自动类型转换、强制类型转换、作用域、整型表数范围

一.变量的作用域 测试代码: public class Test1 { private static int value = 1; // 全局变量 private static int temp = 0; // 全局变量 public static void main(String[] args) { int value = 2; // 局域变量覆盖全局变量 System.out.println(value); // 输出的是局域变量,全局变量被屏蔽 System.out.println(tem

高版本自动接听电话方法

原文地址:http://www.eoeandroid.com/forum.php?mod=viewthread&tid=894679&page=1&_dsign=b92c470b 高版本自动接听电话方法:             try {                 Method method = Class.forName("android.os.ServiceManager")                         .getMethod(&q

第二十一篇 Java 数据类型的定义 ,以及基础类型的自动转换和强制转换

大家好,今天呢我吧我所学到的一些知识点共享给大家,希望大家看完之后,要是有什么不懂的,请随时联系我,要是觉得我写的不是很好的 ,还希望你们能够谅解一下,因为小弟我刚学会写博客也没多久,很多格式和方法都不是很完善,希望大家多多包涵,好了 废话就不多说了,来谈一下今天我所学到的一些知识点吧: 今天我主要是学到了一些Java中的数据类型,其中,Java中的数据类型分为俩类------基础数据类和逻辑数据类,下面我所介绍的都是基本数据类的一些分类,至于逻辑类,由于使用次数过少,所以今天就不再这里多做介绍

9.Java数据类型转换(自动转换和强制转换)

数据类型的转换,分为自动转换和强制转换.自动转换是程序在执行过程中“悄然”进行的转换,不需要用户提前声明,一般是从位数低的类型向位数高的类型转换:强制类型转换则必须在代码中声明,转换顺序不受限制. 自动数据类型转换 自动转换按从低到高的顺序转换.不同类型数据间的优先关系如下:     低--------------------------------------------->高     byte,short,char-> int -> long -> float -> do

自动转换和强制转换

package review20140420;/* * 自动转换和强制转换 */public class Test1 {    //程序的入口    public static void main(String[] args) {        //定义变量a,b        int a=256;        byte b=15;        //自动转换        int a1=(int)b;        //强制转换        byte b1=(byte)a;        

【转载】mysql binlog日志自动清理及手动删除

说明:当开启mysql数据库主从时,会产生大量如mysql-bin.00000* log的文件,这会大量耗费您的硬盘空间.mysql-bin.000001mysql-bin.000002mysql-bin.000003mysql-bin.000004mysql-bin.000005…有三种解决方法:1.关闭mysql主从,关闭binlog:2.开启mysql主从,设置expire_logs_days:3.手动清除binlog文件,> PURGE MASTER LOGS TO ‘MySQL-bin

iOS 版本自动更新

AppDelegate.h - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    [self  editionUpdate]; } //版本自动更新 -(void)editionUpdate{    NSString * [email protected]"192.168.......";//获取后台的接口