iOS Rotation

iOS屏幕旋转学习笔记
iOS开发中使用屏幕旋转功能的相关方法

1、基本知识点解读

了解屏幕旋转首先需要区分两种 orientation
1.1、device orientation
设备的物理方向
1.2、interface orientation
界面显示的方向

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

2、屏幕旋转的流程

加速计是整个IOS屏幕旋转的基础。
依赖加速计,设备才可以判断出当前的设备方向。
当加速计检测到方向变化的时候,会发出
UIDeviceOrientationDidChangeNotification 通知。
屏幕旋转的流程如下:
1>、加速计来识别设备的旋转方向。
发送 UIDeviceOrientationDidChangeNotification 设备旋转的通知。
2>、app 接收到旋转事件(通知事件)。
2>、app 通过AppDelegate通知当前程序的KeyWindow。
3>、Window 会知会它的 rootViewController,判断该view controller所支持的旋转方向,完成旋转。
4>、如果存在 modal 的view controller的话,系统则会根据 modal 的view controller,来判断是否要进行旋转。

UIDevice 对象可以选择性的(是否)接收
UIDeviceOrientationDidChangeNotification 通知。

// 是否已经开启了设备方向改变的通知
@property(nonatomic,readonly,getter=isGeneratingDeviceOrientationNotifications)
BOOL generatesDeviceOrientationNotifications
__TVOS_PROHIBITED;

// 开启接收接收 UIDeviceOrientationDidChangeNotification 通知
- (void)beginGeneratingDeviceOrientationNotifications
__TVOS_PROHIBITED;     // nestable

// 结束接收接收 UIDeviceOrientationDidChangeNotification 通知
- (void)endGeneratingDeviceOrientationNotifications__TVOS_PROHIBITED;


在 app 代理里面结束接收 设备旋转的通知事件, 后续的屏幕旋转都会失效

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    // 结束接收接收 UIDeviceOrientationDidChangeNotification 通知
    [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
    return YES;
}

3、如何决定interface orientation (界面方向)

3.1、全局控制
Info.plist文件中,有一个Supported interface orientations,可以配置整个应用的屏幕方向,此处为 全局控制
3.2、UIWindow
iOS6的UIApplicationDelegate提供了下述方法,能够指定 UIWindow 中的界面的屏幕方向:

// 该方法默认值为 Info.plist 中配置的 Supported interface orientations 项的值。
- (NSUInteger)application:(UIApplication *)application  supportedInterfaceOrientationsForWindow:(UIWindow *)window  NS_AVAILABLE_IOS(6_0); 

iOS中通常只有一个 window,所以此处的控制也可以视为全局控制。
3.3、controller (单个界面控制)
只有以下两种情况:
当前 controller 是 window 的 rootViewController
当前 controller 是 modal 模式的时(controller 为 modal 显示的控制器),orientations相关方法才会起作用(才会被调用),当前controller及其所有的childViewController都在此作用范围内。

3.4、最终支持的屏幕方向
一个界面最后支持的屏幕方向,是取 (全局控制 ∩ UIWindow 中的界面控制 ∩ 单个界面控制)
的交集。
如果全局控制支持所有屏幕方向,UIWindow 中的界面控制支持横屏,当个界面中只是支持横屏向右,那么最后界面只会以横屏向右显示,并且不支持旋转到其他的方向。

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

4、API 使用讲解

4.1**UIViewController Rotation 的 api **


// To make it more convenient for applications to adopt rotation, a view controller may implement the below methods. Your UIWindow's frame should use [UIScreen mainScreen].bounds as its frame.
// 为了让控制器更加方便的旋转,视图控制器可以实现下面这些方法。你的 UIWindow 的 frame 将要使用 UIScreen mainScreen].bounds 作为他的 frame。

@interface UIViewController (UIViewControllerRotation)

// call this method when your return value from shouldAutorotateToInterfaceOrientation: changes
// 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:

//  试着去旋转到界面的方向
// 使用场景是 interface orientation和device orientation 不一致,
// 希望通过重新指定 interface orientation 的值,立即实现二者一致;
// 如果这时只是更改了支持的 interface orientation 的值,没有调用attemptRotationToDeviceOrientation,那么下次 device orientation 变化的时候才会实现二者一致,关键点在于能不能立即实现。
+ (void)attemptRotationToDeviceOrientation NS_AVAILABLE_IOS(5_0) __TVOS_PROHIBITED;

// Applications should use supportedInterfaceOrientations and/or shouldAutorotate..  
// 应用将要使用界面支持的方向,或者将要自动旋转 (在 iOS6 以后被禁用, 要兼容 iOS 6 还是需要实现这个方法)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation NS_DEPRECATED_IOS(2_0, 6_0) __TVOS_PROHIBITED;

// New Autorotation support.  
// 新的自动旋转的支持 (上面的方法被下面两个方法替代)

// 将要自动旋转 (在 iOS6 开始启用)返回 yes 为支持旋转,no 为不支持旋转
- (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;

// 支持的界面方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;

// Returns interface orientation masks.
// 返回现在正在显示的用户界面方向
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;

// The rotating header and footer views will slide out during the rotation and back in once it has completed.
- (nullable UIView *)rotatingHeaderView NS_DEPRECATED_IOS(2_0,8_0, "Header views are animated along with the rest of the view hierarchy") __TVOS_PROHIBITED;     // Must be in the view hierarchy. Default returns nil.
- (nullable UIView *)rotatingFooterView NS_DEPRECATED_IOS(2_0,8_0, "Footer views are animated along with the rest of the view hierarchy") __TVOS_PROHIBITED;     // Must be in the view hierarchy. Default returns nil.

// 获取用户界面的方向 (方法在 iOS8 被禁用,方法是只读的)
@property(nonatomic,readonly) UIInterfaceOrientation interfaceOrientation NS_DEPRECATED_IOS(2_0,8_0) __TVOS_PROHIBITED;

// Notifies when rotation begins, reaches halfway point and ends.
// 当旋转开始,到达一半,结束的时候,将通过下列方法得到通知。

// 将要旋转到用户界面
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration NS_DEPRECATED_IOS(2_0,8_0, "Implement viewWillTransitionToSize:withTransitionCoordinator: instead") __TVOS_PROHIBITED;

// 已经从某个用户界面开始旋转
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation NS_DEPRECATED_IOS(2_0,8_0) __TVOS_PROHIBITED;

// 将要动画旋转到用户界面
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration NS_DEPRECATED_IOS(3_0,8_0, "Implement viewWillTransitionToSize:withTransitionCoordinator: instead") __TVOS_PROHIBITED;

// 界面切换到一半的控制
- (void)willAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration NS_DEPRECATED_IOS(2_0, 5_0) __TVOS_PROHIBITED;
- (void)didAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation NS_DEPRECATED_IOS(2_0, 5_0) __TVOS_PROHIBITED; // The rotating header and footer views are offscreen.
- (void)willAnimateSecondHalfOfRotationFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation duration:(NSTimeInterval)duration NS_DEPRECATED_IOS(2_0, 5_0) __TVOS_PROHIBITED; // A this point, our view orientation is set to the new orientation.

@end

4.2 api 的说明

// Applications should use supportedInterfaceOrientations and/or shouldAutorotate.. 
// 应用将要使用界面支持的方向,或者将要自动旋转 (在 iOS6 以后被禁用, 要兼容 iOS 6 还是需要实现这个方法)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation NS_DEPRECATED_IOS(2_0, 6_0) __TVOS_PROHIBITED;

这一个接口被下面两个接口替代 (在 iOS6 以后)

// 将要自动旋转 (在 iOS6 开始启用)返回 yes 为支持旋转,no 为不支持旋转
- (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;

// 支持的界面方向 (在 iOS6 开始启用)
- (UIInterfaceOrientationMask)supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;

如果需要兼容 iOS6 之前的系统还是需要实现老的接口,要不 app 只能支持竖屏不能旋转

4.3 api 接口的简单使用 (iOS 6 之后)

当只需要锁定屏幕的旋转不需要设置屏幕的旋转方向 ( 方向固定是竖直)

// 是否支持屏幕旋转
-(BOOL)shouldAutorotate {
    return NO;
}

开启屏幕旋转并设置屏幕旋转支持的方向

// 是否支持屏幕旋转 (返回 NO 后面俩方法不调用,后面只支持竖直方向)
-(BOOL)shouldAutorotate {
    return NO;
}
// 支持屏幕旋转的方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    
  //  通过设置返回的枚举值来改变屏幕旋转支持的方向 
  //(iPad上的默认返回值是UIInterfaceOrientationMaskAll,
  //  iPhone上的默认返回值是UIInterfaceOrientationMaskAllButUpsideDown)
    return UIInterfaceOrientationMaskAll;
}

// Returns interface orientation masks. (返回最优先显示的屏幕方向)
// 同时支持Portrait和Landscape方向,但想优先显示Landscape方向,那软件启动的时候就会先显示Landscape,在手机切换旋转方向的时候仍然可以在Portrait和Landscape之间切换;
// 返回现在正在显示的用户界面方向
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {

};

** 屏幕旋转设置注意点:**
在iOS 4 and 5,都是由具体的view controller来决定对应的view的orientation设置。
而在iOS 6,则是由 top-most controller来决定 view 的 orientation 设置。

举个例子:
你的app的rootViewController是navigation controller "nav", 在”nav"里的stack依次是:main view -> sub view > sub sub view,而main view里有一个button会present modal view "modal view".

那么for ios 4 and 5,在ipad里,如果你要上述view都仅支持横屏orientation,你需要在上面的main view, sub view, sub sub view, model view里都添加:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {  
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation==UIInterfaceOrientationLandscapeRight);  
}  

而对于iOS6, 由于是由 top-most controller 来设置 orientation,因此你在main view, sub view, sub sub view里添加下面的代码是没有任何效果的,
而应该是在nav controller里添加下列代码。
而modal view则不是在nav container里,因此你也需要在 modal view controller 里也添加下列代码。

- (BOOL)shouldAutorotate  {  
    return YES;  
}  

-(NSUInteger)supportedInterfaceOrientations {  
    return UIInterfaceOrientationMaskLandscape;  
}  

** 注意:**
你需要自定义一个UINavigationController的子类for "nav controller",这样才可以添加上述代码。和navigation controller类似,tab controller里的各个view的orientation设置应该放在tab controller里

** api 说明:**
** attemptRotationToDeviceOrientation 使用说明:**

// call this method when your return value from shouldAutorotateToInterfaceOrientation: changes 
// 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: 
// 该方法的使用场景是 interface orientation和device orientation 不一致,但希望通过重新指定 interface orientation 的值,立即实现二者一致;
// 如果这时只是更改了支持的 interface orientation 的值,没有调用attemptRotationToDeviceOrientation,那么下次 device orientation 变化的时候才会实现二者一致,关键点在于能不能立即实现。
+ (void)attemptRotationToDeviceOrientation {
      // code
}

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

** supportedInterfaceOrientations 使用说明: **
此方法返回当前viewController 支持的方向. 但是, 只有两种情况下此方法才会生效:
1、当前viewController是window的rootViewController.
2、当前viewController是modal模式的. 即, 此viewController是被调用
presentModalViewController 而显示出来的.

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

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

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

** preferredInterfaceOrientationForPresentation 使用说明: **
此方法也仅有在当前viewController是rootViewController或者是modal模式时才生效.

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

5、实现屏幕的旋转

5.1、在 iOS6 之后存在竖屏幕固定和需要进行旋转的界面的需求配置:

for ios6的top-most controller决定orientation设置,导致这样一个问题:
在 top-most controller里的views无法拥有不相同的orientation设置。
例如:for iphone, 在nav controller里,你有main view, sub view and sub sub view,前2个都只能打竖,而sub sub view是用来播放video,可以打横打竖。
那么在ios 4 and 5里可以通过在main view and sub view的shouldAutorotateToInterfaceOrientation里设置只能打竖,而在sub sub view的shouldAutorotateToInterfaceOrientation设置打竖打横即可。
而在ios 6里则无法实现这种效果,因为在main view, sub view and sub sub view的orientation设置是无效的,只能够在nav controller里设置。那么你可能想着用下列代码在nav controller里控制哪个view打竖,哪个view打横:

-(NSUInteger)supportedInterfaceOrientations{  
    if([[self topViewController] isKindOfClass:[SubSubView class]])  
        return UIInterfaceOrientationMaskAllButUpsideDown;  
    else  
        return UIInterfaceOrientationMaskPortrait;  
}  

是的,这样可以使得在main view and sub view里无法打横,而sub sub view横竖都行。但问题来了,如果在sub sub view时打横,然后back to sub view,那么sub view是打横显示的!

目前想到的解决方法只能是把sub sub view脱离nav controller,以modal view方式来显示。
这样就可以在modal view里设置打横打竖,而在nav controller里设置只打竖。

说了那么多,其实如果你的app的所有view的orientation的设置是统一的,那么你可以简单的在plist file里设置即可,不用添加上面的代码。而如果你添加了上面的代码,就会覆盖plist里orientation的设置。

in iOS 6, 当view controller present时,
不会call willRotateToInterfaceOrientation:duration:,
willAnimateRotationToInterfaceOrientation:duration:,
and didRotateFromInterfaceOrientation: methods,只有在发生rotate的时候才会call。

5.2、强制旋转

iOS两个强制旋转屏幕的方法
有时候, 需要不随系统旋转, 而是强制旋转到某一个角度. 最典型的场景就是视频播放器, 当点击了全屏按钮的时候, 需要横过来显示.
对于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 的方法来实现.

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

//设置statusBar
[[UIApplication sharedApplication] setStatusBarOrientation:orientation];
//计算旋转角度
float arch;
if (orientation == UIInterfaceOrientationLandscapeLeft)  { 
      rch = -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并不知道你偷偷摸摸干了这些事情, 所以没法帮你自动设置.

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 方法即可.

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

[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait]; 

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

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

关于手动旋转的设置:

方式一、直接设置 UIDevice 的 orientation (可能被拒)

if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {  
    [[UIDevice currentDevice] performSelector:@selector(setOrientation:) withObject:(id)UIInterfaceOrientationPortrait];  
} 

方式二、没有改变 UIDevice 的 orientation,而是改变某个view的 transform,利用 CGAffineTransformMakeRotation 来达到目的,比如:

self.view.transform = CGAffineTransformMakeRotation(M_PI/2) 

下面讲解采用第二种方式的各版本手动旋转:思想是首先设置 statusBarOrientation,然后再改变某个view的方向跟 statusBarOrientation 一致!
IOS6手动旋转:

  1. 那既然是旋转,最少也得有2个方向,那么还是少不了上面说的那个硬性条件,先在plist里面设置好所有可能需要旋转的方向。既然是手动旋转,那么就要关闭自动旋转:
- (BOOL)shouldAutorotate{  
        return NO;  
}  

2.手动触发某个按钮,调用方法,这个方法的实现如下:

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];  
self.view.transform = CGAffineTransformMakeRotation(M_PI/2);  
self.view.bounds = CGRectMake(0, 0, kScreenHeight, 320);  

注意:

  1. 只需要改变self.view.transform,那么self.view的所有subview都会跟着自动变;其次因为方向变了,所以self.view的大小需要重新设置,不要使用self.view.frame,而是用bounds。
  2. 如果shouldAutorotate 返回YES的话,下面设置setStatusBarOrientation 是不管用的!setStatusBarOrientation只有在shouldAutorotate 返回NO的情况下才管用!

IOS5、IOS4手动旋转:

  • (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
    return (interfaceOrientation == [UIApplication sharedApplication].statusBarOrientation);
    }
    1.在需要手动旋转的viewController里的 shouldAutorotateToInterfaceOrientation 方法设置 interfaceOrientation == [UIApplicationsharedApplication].statusBarOrientation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{  
    return (interfaceOrientation == [UIApplication sharedApplication].statusBarOrientation);  
}  

2.手动触发某个按钮,调用方法,这个方法的实现如下:

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];  
self.view.transform = CGAffineTransformMakeRotation(M_PI/2);  
self.view.bounds = CGRectMake(0, 0, kScreenHeight, 320);  

注意:只需要改变self.view.transform,那么self.view的所有subview都会跟着自动变;其次因为方向变了,所以self.view的大小需要重新设置,不要使用self.view.frame,而是用bounds。

经验分享:
1.IOS6里面,如果一个项目里面需要各种旋转支持,有自动,有手动,那么我们可以新建2个navController或者tabbarController的子类,一个是不旋转,一个旋转,那么所有需要旋转的UINavigationController都可以用这个子类来代替!包括我们可以定制短信呀、邮件呀的旋转!2.supportedInterfaceOrientations 方法一般是写UIInterfaceOrientationMask方向,但是如果程序要兼容4.3以下的SDK(4.3以下的SDK必须是4.5以下的Xcode,不支持IOS6),那么在用4.5以下的Xcode编译的时候通不过!所以可以用statusBarOrientation代替或者直接写死数字!

-(NSUInteger)supportedInterfaceOrientations{  
    return [UIApplication sharedApplication].statusBarOrientation;  
}  

3.一般都不建议在程序里面直接调用 UIDeviceOrientation 的方向,而是用 UIInterfaceOrientation,他们之间是不同的!

UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,  
UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft  

UIApplication.h


// Note that UIInterfaceOrientationLandscapeLeft is equal to UIDeviceOrientationLandscapeRight (and vice versa).
// This is because rotating the device to the left requires rotating the content to the right.
typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
    UIInterfaceOrientationUnknown            = UIDeviceOrientationUnknown,
    UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait,
    UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
    UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight,
    UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft
} __TVOS_PROHIBITED;

/* This exception is raised if supportedInterfaceOrientations returns 0, or if preferredInterfaceOrientationForPresentation
   returns an orientation that is not supported.
*/
UIKIT_EXTERN NSString *const UIApplicationInvalidInterfaceOrientationException NS_AVAILABLE_IOS(6_0) __TVOS_PROHIBITED;

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),
} __TVOS_PROHIBITED;

以组合的方式更加方便的使用这些枚举值

万能的stackoverflow上提供了一种主动触发的方式:
UIViewController *vc = [[UIViewController alloc]init]; 
[self presentModalViewController:vc animated:NO]; 
[self dismissModalViewControllerAnimated:NO]; 
[vc release]; 
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容