此博文主要针对IOS应用, 是屏幕旋转相关问题的一个总结. 主要内容有:

  1. IOS5,6,7不同版的适配.
  2. 强制旋转和自动旋转.

  • 博客: http://www.cnblogs.com/jhzhu
  • 邮箱: jhzhuustc@gmail.com
  • 作者: 知明所以
  • 时间: 2013-12-12

改变Orientation的三种途径

这里, 咱们主要理清一下: 到底有哪些设置可以改变屏幕旋转特性. 这样:

  • 出现任何问题我们都可以从这几个途径中发现原因.
  • 灵活应付产品经理的各种需求.

首先我们得知道:

  1. 当手机的重力感应打开的时候, 如果用户旋转手机, 系统会抛发UIDeviceOrientationDidChangeNotification 事件.
  2. 您可以分别设置ApplicationUIViewcontroller支持的旋转方向.Application的设置会影响整个App, UIViewcontroller的设置仅仅会影响一个viewController(IOS5和IOS6有所不同,下面会详细解释).
  3. UIKit收到UIDeviceOrientationDidChangeNotification事件的时候, 会根据ApplicationUIViewcontroller的设置, 如果双方都支持此方向, 则会自动屏幕旋转到这个方向. 更code的表达就是, 会对两个设置求,得到可以支持的方向. 如果求之后,没有任何可支持的方向, 则会抛发UIApplicationInvalidInterfaceOrientationException异常.

Info.plist设置

在App的Info.plist里设置:

key xcode name Summary avilable value
UIInterfaceOrientation initial interface orientation Specifies the initial orientation of the app’s user interface. UIInterfaceOrientationPortrait,
UIInterfaceOrientationPortraitUpsideDown,
UIInterfaceOrientationLandscapeLeft,
UIInterfaceOrientationLandscapeRight
UISupportedInterfaceOrientations Supported interface orientations Specifies the orientations that the app supports. UIInterfaceOrientationPortrait,
UIInterfaceOrientationPortraitUpsideDown,
UIInterfaceOrientationLandscapeLeft,
UIInterfaceOrientationLandscapeRight

在Info.plist中设置之后,这个app里所有的viewController支持的自动旋转方向都只能是app支持的方向的子集.

UIViewController

IOS6 and above

supportedInterfaceOrientations

在IOS6及以上的版本中, 增添了方法UIViewController.supportedInterfaceOrientations. 此方法返回当前viewController支持的方向. 但是, 只有两种情况下此方法才会生效:

  1. 当前viewControllerwindowrootViewController.
  2. 当前viewControllermodal模式的. 即, 此viewController是被调用presentModalViewController而显示出来的.

在以上两种情况中,UIViewController.supportedInterfaceOrientations方法会作用于当前viewController和所有childViewController. 以上两种情况之外, UIKit并不会理会你的supportedInterfaceOrientations方法.

举个栗子:

- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft;
}

如果某个viewController实现了以上方法. 则, 此viewController就支持竖方向和左旋转方向. 此viewController的所有childViewController也同时支持这两个方向, 不多不少.

preferredInterfaceOrientationForPresentation

此方法也属于UIViewController. 影响当前viewController的初始显示方向. 此方法也仅有在当前viewControllerrootViewController或者是modal模式时才生效.

shouldAutorotate

此方法,用于设置当前viewController是否支持自动旋转. 如果,你需要viewController暂停自动旋转一小会儿. 那么可以通过这个方法来实现.同样的, 此方法也仅有在当前viewControllerrootViewController或者是modal模式时才生效.

IOS5 and before

在IOS5和以前的版本中, 每个viewController都可以指定自己可自动旋转的方向.(这样不是挺好么?苹果那帮工程师为啥要搞成这样...).
每当UIkit收到UIDeviceOrientationDidChangeNotification消息的时候, 就会用以下方法询问当前显示的viewController支不支持此方向:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
{
if ((orientation == UIInterfaceOrientationPortrait) ||
(orientation == UIInterfaceOrientationLandscapeLeft))
return YES; return NO;
}

特别要注意的是:你必须至少要对一个方向返回YES.(为难系统总不会有啥好事儿,你懂得).

UIView.transform

最后一个方法是设置UIViewtransform属性来强制旋转.
见下代码:

//设置statusBar
[[UIApplication sharedApplication] setStatusBarOrientation:orientation]; //计算旋转角度
float arch;
if (orientation == UIInterfaceOrientationLandscapeLeft)
arch = -M_PI_2;
else if (orientation == UIInterfaceOrientationLandscapeRight)
arch = M_PI_2;
else
arch = 0; //对navigationController.view 进行强制旋转
self.navigationController.view.transform = CGAffineTransformMakeRotation(arch);
self.navigationController.view.bounds = UIInterfaceOrientationIsLandscape(orientation) ? CGRectMake(0, 0, SCREEN_HEIGHT, SCREEN_WIDTH) : initialBounds;

需要注意的是:

  1. 当然我们可以对当前viewController进行旋转, 对任何view旋转都可以.但是, 你会发现navigationBar还横在那里. 所以, 我们最好对一个占满全屏的view进行旋转. 在这里我们旋转的对象是self.navigationController.view, 当然self.window也可以, help yourself~
  2. 我们需要显式的设置bounds. UIKit并不知道你偷偷摸摸干了这些事情, 所以没法帮你自动设置.

如何应付产品经理的需求

有了以上三把武器, 我想基本可以应付BT产品经理所有的需求了. 但是这里还有一些小技巧.

直接锁死

(略)

随系统旋转

IOS5及之前

对于IOS5及之前的版本, 只要在对每个viewController重写shouldAutorotateToInterfaceOrientation方法, 即可方便的控制每个viewController的方向.

IOS6及以后

对于IOS6及以后的版本, 如果想方便的单独控制每个viewController的方向. 则可以使用这样:

  • 对于非modal模式的viewController:

    • 如果不是rootViewController,则重写supportedInterfaceOrientations,preferredInterfaceOrientationForPresentation以及shouldAutorotate方法, 按照当前viewController的需要返回响应的值.
    • 如果是rootViewController,则如下重写方法:
-(NSUInteger)supportedInterfaceOrientations
{
return self.topMostViewController.supportedInterfaceOrientations;
}
-(BOOL)shouldAutorotate
{
return [self.topMostViewController shouldAutorotate];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [self.topMostViewController preferredInterfaceOrientationForPresentation];
}
-(UIViewController*)topMostViewController
{
//找到当前正在显示的viewController并返回.
}

显而易见, 我们巧妙的绕开了UIKit只调用rootViewController的方法的规则. 把决定权交给了当前正在显示的viewController.

  • 对于modal模式的viewController. 则按照需要重写supportedInterfaceOrientations,preferredInterfaceOrientationForPresentation以及shouldAutorotate方法即可.

强制旋转

有时候, 需要不随系统旋转, 而是强制旋转到某一个角度. 最典型的场景就是视频播放器, 当点击了全屏按钮的时候, 需要横过来显示.

  • 对于IOS5及以前的版本, 可以用下面的方法:
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 = UIInterfaceOrientationLandscapeRight;
[invocation setArgument:&val atIndex:2];
[invocation invoke];
}
  • 对于IOS6及以后的版本. UIDevice.setOrientation从隐藏变为移除.只能通过设置UIView.transform的方法来实现.

参考资料

IOS Orientation, 想怎么转就怎么转~~~的更多相关文章

  1. iOS Orientation获取

    [iOS Orientation获取] 1.[[UIDevice sharedInstance] orientation] 必须调用beginGeneratingDeviceOrientationNo ...

  2. iOS Orientation bug

    Every September means pain for iOS developers- you need to make sure your old apps/code run on the n ...

  3. ios输出想保留的整数位(占位符)

    int startHour=5; int startMinute=4; //输出前面补0,不管你输入的数据前面有没有0 sp;NSLog(@"====>%@",[NSStri ...

  4. iOS屏幕旋转 浅析

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

  5. View Programming Guide for iOS ---- iOS 视图编程指南(四)---Views

    Views Because view objects are the main way your application interacts with the user, they have many ...

  6. 分分钟搞定IOS远程消息推送

    一.引言 IOS中消息的推送有两种方式,分别是本地推送和远程推送,本地推送在http://my.oschina.net/u/2340880/blog/405491这篇博客中有详细的介绍,这里主要讨论远 ...

  7. iOS开发中获取WiFi相关信息

    iOS 开发中难免会遇到很多与网络方面的判断,这里做个汇总,大多可能是与WiFi相关的. 1.Ping域名.Ping某IP 有 时候可能会遇到ping 某个域名或者ip通不通,再做下一步操作.这里的p ...

  8. iOS Wi-Fi

    查漏补缺集是自己曾经做过相关的功能,但是重做相关功能或者重新看到相关功能的实现,感觉理解上更深刻.这一类的文章集中记录在查漏补缺集. iOS 开发中难免会遇到很多与网络方面的判断,这里做个汇总,大多可 ...

  9. 【零基础学习iOS开发】【转载】

    原文地址:http://www.cnblogs.com/mjios/archive/2013/04/24/3039357.html 本文目录 一.什么是iOS 二.主流手机操作系统 三.什么是iOS开 ...

随机推荐

  1. kFreeBsd 国内开源镜像站汇总

    从http://bbs.chinaunix.net/archiver/tid-3756178.html这里抽取了debian源中支撑kfreebsd架构的源. 中科大: http://debian.u ...

  2. Hibernate Validator

    http://docs.jboss.org/hibernate/validator/4.2/reference/zh-CN/html_single/#example-group-interfaces

  3. JMS学习(四) Selector详解

    一.前言 在掌握了消息的结构之后,我们接下来看一下JMS的一个重要功能:选择器.有些时候,作为消费者只希望处理自己感兴趣的消息.如果某个消息只有一个消费者,我们可以在让该客户端根据规则来处理自己感兴趣 ...

  4. lnmp+phpmyadmin配置与出现问题

    本博客归moka同学(新浪微博:moka同学)本人亲自整理,如有使用,请加链接注明出处. lnmp 安装完全后,配置phpmyadmin .其访问方式为 http://202.18.400.379/p ...

  5. PHP学习笔记:用php读取xml文件

    xml已经被json逐渐替代,现在用的api都是用貌似用的json,但是有些老的网站还是在用xml. 这里默认xml文件为:address.xml,存放在和读取的php文件相同级别目录,xml内容如下 ...

  6. ubuntu定时执行脚本(crond)

    如果发现您的系统里没有这个命令,请安装下面两个软件包. vixie-cron crontabs crontab 是用来让使用者在固定时间或固定间隔执行程序之用,换句话说,也就是类似使用者的时程表.-u ...

  7. Objective-C学习笔记---构造函数和析构函数

    简单的讲,构造函数就是在创建一个对象的时候起到初始化的作用,对这个对象里的一些成员变量进行初始化,析构函数就是在对象被删除进行一些清理工作,也就是专门的扫尾工作,下面用代码来进行具体说明. 一.构造函 ...

  8. [leetcode] Contains Duplicate

    Contains Duplicate Given an array of integers, find if the array contains any duplicates. Your funct ...

  9. iOS实现(超级猜图)源码

    //首先建立模型文件 QLLQuestion.hheQLLQuestion.m文件 #import <Foundation/Foundation.h> @interface QLLQues ...

  10. CoreAnimation-03-隐式动画

    简介 每个UI控件,默认自动创建一个图层(根图层),即每个UI控件对应于至少一个图层 可以手动创建图层,这些图层为非根图层 对非根图层的某些属性(标记为Animatable的属性)进行修改,默认会自动 ...