此博文主要针对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. scons学习

    http://blog.csdn.net/andyelvis/article/category/948141 http://www.scons.org/doc/production/HTML/scon ...

  2. 【NOIP训练】【数论】超级计算机

    题目描述有以下几个问题:1 给定正整数  求方程  的最小非负整数解.2 给定正整数 求方程 的最小非负整数解.3 给定正整数 求方程  在模  意义下解的数量.4 给定正整数 求   的值.其中   ...

  3. Maven创建webapp(二)

    这一节将记录在myeclipse下用maven创建一个简单的webapp项目 web开发maven仓库自动添加组件,故需要需要保持网络的通畅. 打开myeclipse  -->  File  - ...

  4. php实现快速排序

    下午练习时候,把经典排序快速排序做了,以下是我的代码 <?php /** * Created by PhpStorm. * User: Administrator * Date: 16-8-29 ...

  5. 向java的main()传入大量参数

    项目中有一些用java写成的可执行的工具,需要调用者传入大量的参数.最开始,我使用的是最传统的方式,直接一个传入参数数组,于是有如下这么壮观的代码: public static void main(S ...

  6. ASP.NET检测到有潜在危险的 Request.Form 值解决方案汇总

    ASP.NET检测到有潜在危险的 Request.Form 值解决方案汇总 当我们在网站中使用CKEditor等富文本编辑器时,大多都会遇到这样的到警告 这是因为ASP.NET默认开启对页面提交内容的 ...

  7. JavaScript hasOwnProperty() 函数详解

    hasOwnProperty()函数用于指示一个对象自身(不包括原型链)是否具有指定名称的属性.如果有,返回true,否则返回false. 该方法属于Object对象,由于所有的对象都"继承 ...

  8. Error occurred in deployment step 'Add Solution': Operation is not valid due to the current state of the object.

    Sharepoint 部署的时候出现一个错误 Error occurred in deployment step 'Add Solution': Operation is not valid due ...

  9. Interoperability between Java and SharePoint 2013 on Premises

    http://ctp-ms.blogspot.com/2012/12/interoperability-between-java-and.html   Introduction One of the ...

  10. Android项目实战(十二):解决OOM的一种偷懒又有效的办法

    在程序的manifest文件的application节点加入android:largeHeap=“true” 即可. 对,只需要一句话! 那么这行代码的意思是什么呢? 简单的说就是使该APP获取最大可 ...