0. 应用级别的配置
大家(特指有iOS开发经验的人)应该都知道Xcode Project的工程配置General页签中有那么四个图(或者4个checkbox),标识对四种interfaceOrientation的支持。分别为Portrait、PortraitUpsideDown、LandscapeLeft和LandscapeRight。
对应的,在Xcode Project工程配置的Info页,实际上就是Info.plist中,有对4种Orientation的记录项。
这两者是一样的。
1. Window级别的控制
在iOS6.0之后,UIApplicationDelegate中多了一个方法声明:
1
|
- (
NSUInteger
)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
|
就是对于特定的application和特定的window,我们需要支持哪些interfaceOrientation,这是可以通过实现这个方法定制的。
返回值是一个无符号整数,实际上是可以使用定义好的枚举值:
1
2
3
4
5
6
7
8
9
|
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),
};
|
对于UIApplicationDelegate的这个方法声明,大多数情况下application就是当前的application,而window通常也只有一个。所以基本上通过window对横屏竖屏interfaceOrientation的控制相当于全局的。
2. Controller层面的控制
老版本的iOS有这样一个方法:
1
|
- (
BOOL
)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
NS_DEPRECATED_IOS
(2_0, 6_0);
|
即定制是否可以旋转到特定的interfaceOrientation。
而在iOS6之后,推出了2个新的方法来完成这个任务:
1
2
|
- (
BOOL
)shouldAutorotate
NS_AVAILABLE_IOS
(6_0);
- (
NSUInteger
)supportedInterfaceOrientations
NS_AVAILABLE_IOS
(6_0);
|
可以看得出来,两个和在一起就是原来任务的完成过程。其中,大概的判断方式是,先执行前者,判断是否可以旋转,如果为YES,则根据是否支持特定的interfaceOrientation再做决断。
3. 使得特定ViewController坚持特定的interfaceOrientation
iOS6之后还提供了这样一个方法,可以让你的Controller倔强第坚持某个特定的interfaceOrientation:
1
|
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
NS_AVAILABLE_IOS
(6_0);
|
这就叫坚持,呵呵!
当然,使用这个方法是有前提的,就是当前ViewController是通过全屏的Presentation方式展现出来的。
这里使用的是另外一套枚举量,可以去UIApplication.h中查看定义。
4. 当前屏幕方向interfaceOrientation的获取
有3种方式可以获取到“当前interfaceOrientation”:
- controller.interfaceOrientation,获取特定controller的方向
- [[UIApplication sharedApplication] statusBarOrientation] 获取状态条相关的方向
- [[UIDevice currentDevice] orientation] 获取当前设备的方向
具体区别,可参见StackOverflow的问答:
http://stackoverflow.com/questions/7968451/different-ways-of-getting-current-interface-orientation
5. 容器Controller的支持
上面把interfaceOrientation方向的获取和支持配置都说了,看起来没什么问题了。有没有什么特殊情况?
当你使用TabbarController和NavigationController按照如上做法使用的时候就会有些头疼。
办法不是没有,比较通俗的一种就是——继承实现。
(补充:iOS7之后可以通过delegate对此进行控制)
对使用TabbarController和NavigationController后旋转屏幕的解决补充:(继承实现)
首先要子类化UINavigationController,增加下面三个方法
//返回最上层的子Controller的shouldAutorotate
- (BOOL)shouldAutorotate{
return self.topViewController.shouldAutorotate;
}
//返回最上层的子Controller的supportedInterfaceOrientations
- (NSUInteger)supportedInterfaceOrientations{
return self.topViewController.supportedInterfaceOrientations;
}
//视图默认显示的方向 -(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return self.topViewController.preferredInterfaceOrientationForPresentation;
}
子类 RotateNavigationController 代码如下:
#import <UIKit/UIKit.h>
@interface RotateNavigationController : UINavigationController @end
#import "RotateNavigationController.h"
@implementation RotateNavigationController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self; }
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
//返回最上层的子Controller的shouldAutorotate
- (BOOL)shouldAutorotate{
return self.topViewController.shouldAutorotate;
}
//返回最上层的子Controller的supportedInterfaceOrientations
- (NSUInteger)supportedInterfaceOrientations{
return self.topViewController.supportedInterfaceOrientations;
}
//视图默认显示的方向
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return self.topViewController.preferredInterfaceOrientationForPresentation;
}
@end
这三个方法就是用来控制项目中所有的视图页面的横竖屏切换的。这三个方法是系统级的。不需要自己主动去调用,也会运行。
app启动首先走 main函数,然后main函数调用AppDelegate ,AppDelegate再调用UINavigationController,UINavigationController再调才是你的界面。UINavigationController 继承的也是UIViewController 。但他比UIViewController更进一步。所以我们各个视图的横竖屏控制是由各个控制器来独立控制的,而不再是根控制器。
往后,我们只要在对应的控制器上重写上面的这三个方法即可控制视图的横竖屏。