改变Orientation的三种途径xcode
这里, 我们主要理清一下: 到底有哪些设置能够改变屏幕旋转特性. 这样:app
出现任何问题咱们均可以从这几个途径中发现缘由.ide
灵活应付产品经理的各类需求.spa
首先咱们得知道:code
当手机的重力感应打开的时候, 若是用户旋转手机, 系统会抛发UIDeviceOrientationDidChangeNotification 事件.orm
您能够分别设置Application和UIViewcontroller支持的旋转方向.Application的设置会影响整个App, UIViewcontroller的设置仅仅会影响一个viewController(IOS5和IOS6有所不一样,下面会详细解释).视频
当UIKit收到UIDeviceOrientationDidChangeNotification事件的时候, 会根据Application和UIViewcontroller的设置, 若是双方都支持此方向, 则会自动屏幕旋转到这个方向. 更code的表达就是, 会对两个设置求与,获得能够支持的方向. 若是求与以后,没有任何可支持的方向, 则会抛发UIApplicationInvalidInterfaceOrientationException异常.对象
Info.plist设置事件
在App的Info.plist里设置:ip
key xcode nameSummaryavilable valueUIInterfaceOrientationinitial interface orientationSpecifies the initial orientation of the app’s user interface.UIInterfaceOrientationPortrait,
UIInterfaceOrientationPortraitUpsideDown,
UIInterfaceOrientationLandscapeLeft,
UIInterfaceOrientationLandscapeRightUISupportedInterfaceOrientationsSupported interface orientationsSpecifies the orientations that the app supports.UIInterfaceOrientationPortrait,
UIInterfaceOrientationPortraitUpsideDown,
UIInterfaceOrientationLandscapeLeft,
UIInterfaceOrientationLandscapeRight
在Info.plist中设置以后,这个app里全部的viewController支持的自动旋转方向都只能是app支持的方向的子集.
UIViewControllerIOS6 and abovesupportedInterfaceOrientations
在IOS6及以上的版本中, 增添了方法UIViewController.supportedInterfaceOrientations. 此方法返回当前viewController支持的方向. 可是, 只有两种状况下此方法才会生效:
当前viewController是window的rootViewController.
当前viewController是modal模式的. 即, 此viewController是被调用presentModalViewController而显示出来的.
在以上两种状况中,UIViewController.supportedInterfaceOrientations方法会做用于当前viewController和全部childViewController. 以上两种状况以外, UIKit并不会理会你的supportedInterfaceOrientations方法.
举个栗子:
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft;
}
若是某个viewController实现了以上方法. 则, 此viewController就支持竖方向和左旋转方向. 此viewController的全部childViewController也同时支持这两个方向, 很少很多.
preferredInterfaceOrientationForPresentation
此方法也属于UIViewController. 影响当前viewController的初始显示方向. 此方法也仅有在当前viewController是rootViewController或者是modal模式时才生效.
shouldAutorotate
此方法,用于设置当前viewController是否支持自动旋转. 若是,你须要viewController暂停自动旋转一小会儿. 那么能够经过这个方法来实现.一样的, 此方法也仅有在当前viewController是rootViewController或者是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
最后一个方法是设置UIView的transform属性来强制旋转.
见下代码:
//设置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;
须要注意的是:
固然咱们能够对当前viewController进行旋转, 对任何view旋转均可以.可是, 你会发现navigationBar还横在那里. 因此, 咱们最好对一个占满全屏的view进行旋转. 在这里咱们旋转的对象是self.navigationController.view, 固然self.window也能够, help yourself~
咱们须要显式的设置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两个强制旋转屏幕的方法
Supporting Multiple Interface Orientations