iOS屏幕旋转学习笔记

一、两种orientation

了解屏幕旋转首先需要区分两种orientation

 

1、device orientation

设备的物理方向

 

2、interface orientation

界面显示的方向

 

iOS提供了在设备旋转时,界面显示发生相应适配的能力,以达到方便用户使用并提供最佳显示效果的目的。开发者需要指定应用支持的显示方向,并对界面显示做出对应的适配。由于界面适配的工作量相当大,目前国内的应用大都只支持默认的竖屏方向。

 

二、相关枚举定义

1、iOS 5和之前版本(后文均简称iOS5):


  1. typedef NS_ENUM(NSInteger, UIInterfaceOrientation) { 
  2.     UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait, 
  3.     UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown, 
  4.     UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight, 
  5.     UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft 
  6. }; 

 

2、iOS 6和之后版本(后文均简称iOS6)又新增了:


  1. typedef NS_OPTIONS(NSUInteger, UIInterfaceOrientationMask) { 
  2.     UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait), 
  3.     UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft), 
  4.     UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight), 
  5.     UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown), 
  6.     UIInterfaceOrientationMaskLandscape = (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight), 
  7.     UIInterfaceOrientationMaskAll = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown), 
  8.     UIInterfaceOrientationMaskAllButUpsideDown = (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight), 
  9. }; 

 

iOS 6使用 NS_OPTIONS 的方式重新定义了UIInterfaceOrientationMaskPortrait、UIInterfaceOrientationMaskLandscapeLeft、UIInterfaceOrientationMaskLandscapeRight、UIInterfaceOrientationMaskPortraitUpsideDown几种基础枚举,这就意味着能以组合的方式更加方便的使用这些枚举值。

 

三、相关方法

1、iOS 5中控制屏幕旋转的方法:


  1. // Applications should use supportedInterfaceOrientations and/or shouldAutorotate.. 
  2. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation NS_DEPRECATED_IOS(2_0, 6_0); 

如果打算支持 toInterfaceOrientation 对应的方向就返回 YES,否则返回 NO。

 

2、iOS6中控制屏幕旋转相关方法:


  1. // New Autorotation support. 
  2. - (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0); 
  3. - (NSUInteger)supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0); 
  4. // Returns interface orientation masks. 
  5. - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation NS_AVAILABLE_IOS(6_0); 

 

第一个方法决定是否支持多方向旋转屏,如果返回NO则后面的两个方法都不会再被调用,而且只会支持默认的UIInterfaceOrientationMaskPortrait方向;

 

第二个方法直接返回支持的旋转方向,该方法在iPad上的默认返回值是UIInterfaceOrientationMaskAll,iPhone上的默认返回值是UIInterfaceOrientationMaskAllButUpsideDown,详情见官方Q&A文档;

 

第三个方法返回最优先显示的屏幕方向,比如同时支持Portrait和Landscape方向,但想优先显示Landscape方向,那软件启动的时候就会先显示Landscape,在手机切换旋转方向的时候仍然可以在Portrait和Landscape之间切换;

 

3、attemptRotationToDeviceOrientation方法

从iOS 5开始有了这个新方法:


  1. // call this method when your return value from shouldAutorotateToInterfaceOrientation: changes 
  2. // if the current interface orientation does not match the current device orientation, a rotation may occur provided all relevant view controllers now return YES from shouldAutorotateToInterfaceOrientation: 
  3. + (void)attemptRotationToDeviceOrientation NS_AVAILABLE_IOS(5_0); 

该方法的使用场景是 interface orientation和device orientation 不一致,但希望通过重新指定 interface orientation 的值,立即实现二者一致;如果这时只是更改了支持的 interface orientation 的值,没有调用attemptRotationToDeviceOrientation,那么下次 device orientation 变化的时候才会实现二者一致,关键点在于能不能立即实现。

 

举个例子:

假设当前的 interface orientation 只支持 Portrait,如果 device orientation 变成 Landscape,那么 interface orientation 仍然显示 Portrait;

 

如果这时我们希望 interface orientation 也变成和 device orientation 一致的 Landscape,以iOS 6 为例,需要先将 supportedInterfaceOrientations 的返回值改成Landscape,然后调用 attemptRotationToDeviceOrientation方法,系统会重新询问支持的 interface orientation,已达到立即更改当前 interface orientation 的目的。

 

四、如何决定interface orientation

1、全局控制

Info.plist文件中,有一个Supported interface orientations,可以配置整个应用的屏幕方向,此处为全局控制。

 

2、UIWindow

iOS6的UIApplicationDelegate提供了下述方法,能够指定 UIWindow 中的界面的屏幕方向:


  1. - (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window  NS_AVAILABLE_IOS(6_0); 

该方法默认值为 Info.plist 中配置的 Supported interface orientations 项的值。

 

iOS中通常只有一个 window,所以此处的控制也可以视为全局控制。

 

3、controller

只有以下两种情况:

当前controller是window的rootViewController

当前controller是modal模式的时,orientations相关方法才会起作用(才会被调用),当前controller及其所有的childViewController都在此作用范围内。

 

4、最终支持的屏幕方向

前面所述的3种控制规则的交集就是一个controller的最终支持的方向;

 

如果最终的交集为空,在iOS6以后会抛出UIApplicationInvalidInterfaceOrientationException崩溃异常。

 

四、强制屏幕旋转

如果interface和device方向不一样,想强制将interface旋转成device的方向,可以通过attemptRotationToDeviceOrientation实现,但是如果想将interface强制旋转成任一指定方向,该方式就无能为力了。

 

不过聪明的开发者们总能想到解决方式:

 

1、私有方法


  1. [[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait]; 

 

但是现在苹果已经将该方法私有化了,越狱开发的同学可以试试。

 

2、旋转view的transform

也可以通过旋转view的transform属性达到强制旋转屏幕方向的目的,但个人感觉这不是靠谱的思路,可能会带来某些诡异的问题。

 

3、主动触发 orientation 机制

要是能主动触发系统的 orientation 机制,调用 orientation 相关方法,使新设置的 orientation 值起作用就好了。这样只要提前设置好想要支持的 orientation,然后主动触发 orientation 机制,便能实现将 interface orientation旋转至任意方向的目的。

 

万能的stackoverflow上提供了一种主动触发的方式:

 

在iOS 4和iOS 6以后:


  1. UIViewController *vc = [[UIViewController alloc]init]; 
  2. [self presentModalViewController:vc animated:NO]; 
  3. [self dismissModalViewControllerAnimated:NO]; 
  4. [vc release]; 

 

iOS 5中:


  1. UIWindow *window = [[UIApplication sharedApplication] keyWindow]; 
  2. UIView *view = [window.subviews objectAtIndex:0]; 
  3. [view removeFromSuperview]; 
  4. [window addSubview:view]; 

 

这种方式会触发UIKit重新调用controller的orientation相关方法,以达到在device方向不变的情况下改变interface方向的目的。

 

虽然不优雅,但却能解决问题,凑合吧。。

 

PS:

话说iOS8中的屏幕旋转相关方法又变化了,表示适配起来很蛋疼。

时间: 2024-11-02 19:49:06

iOS屏幕旋转学习笔记的相关文章

ios屏幕旋转

屏幕旋转 // ios 5.6都有这个方法 - (BOOL)shouldAutorotate{     returnYES; } //ios6有效  - (NSUInteger)supportedInterfaceOrientations{     returnUIInterfaceOrientationMaskLandscape; }   //ios5有效  - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientati

ios 屏幕旋转-IOS实现单个ViewController屏幕旋转?

问题描述 IOS实现单个ViewController屏幕旋转? 如何像微博那样只有在查看图片的ViewController中使得屏幕可以旋转? 解决方案 iOS 5.1实现旋转屏幕 解决方案二: 只在对应的controller打开屏幕旋转,实现代理方法即可

iOS开发:学习笔记—变量、属性、方法、实现

  1.代码说明: Person.h 开发:学习笔记-变量.属性.方法.实现-"> Person.h #import @interface Person : NSObject { int age,sex;//变量的定义 int height,width; } @property int age,sex;//属性的定义 @property char height; //-(void) setAge; -(int) setAge1 :(int)a; -(int) setWH :(int)w :

iOS 6中控制屏幕旋转支持方向的方法

在iOS5.1 和 之前的版本中, 我们通常利用 shouldAutorotateToInterfaceOrientation: 来单独控制某个UIViewController的旋屏方向支持,比如: - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return (interfaceOrientation == UIInterfaceOrientationPo

iOS开发中使用屏幕旋转功能的相关方法_IOS

加速计是整个IOS屏幕旋转的基础,依赖加速计,设备才可以判断出当前的设备方向,IOS系统共定义了以下七种设备方向:   复制代码 代码如下: typedef NS_ENUM(NSInteger, UIDeviceOrientation) {     UIDeviceOrientationUnknown,     UIDeviceOrientationPortrait,            // Device oriented vertically, home button on the bot

ios-IOS中整个工程是设置了支持屏幕旋转,那么如何禁止其中某个视图旋转呢?

问题描述 IOS中整个工程是设置了支持屏幕旋转,那么如何禁止其中某个视图旋转呢? 如题,整个项目中其他视图都是可以旋转的,但是,现在希望其中一个视图只能保持纵向,不允许旋转. 用什么代码有效? 在要禁止的视图中,加入了下面的代码,无效. (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { return (toInterfaceOrientation == UII

处理iOS设备的屏幕旋转

某些情况下,不强制的给用户唯一的屏幕角度给用户.这样用户可以旋转手机得到不同的视觉体验. 最简单的就是safari,横看竖看都可以. 这时需要捕捉用户的屏幕旋转事件并处理.很简单,才两步.比把大象装冰箱都简单. 下面是代码: 1 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 2 { 3 self = [super initWithNibName:nibNameOrNil bundl

ios调用外部SDK后导致的屏幕旋转错误

问题描述 ios调用外部SDK后导致的屏幕旋转错误 程序是用C++写的跨平台横屏游戏,渲染引擎是opengl那套,IOS版添加友盟分享的SDK时,进入友盟封装的界面,游戏就变竖屏了,并且IOS6以下版本没有这个问题. IOS6以上版本是通过UIViewController控制,IOS5以下版本通过AddSubview方式添加view. 友盟的第一个界面是UINavigationController 解决方案 应该还是哪里没整对,第一个view controller 最好是UINavigation

iOS屏幕适配-iOS笔记

学习目标 1.[了解]屏幕适配的发展史 2.[了解]autoResizing基本用法 3.[掌握]autoLayout 的基本用法 4.[掌握]autoLayout代码实现 5.[理解]sizeClass的基本用法 一.屏幕适配的发展史 随着iOS屏幕尺寸越来越多样化,屏幕适配也就越来越重要了. iphone1 - iphone3gs时代,window的size固定为(320,480).我们只需要简单计算一下相对位置就好了,不需要做屏幕适配. iphone4 - iphone4s时代,苹果推出了