改變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