此博文主要針對IOS應用, 是螢幕旋轉相關問題的一個總結. 主要内容有:
IOS5,6,7不同版的适配.
強制旋轉和自動旋轉.
- 部落格: http://www.cnblogs.com/jhzhu
- 郵箱: [email protected]
- 作者: 知明是以
- 時間: 2013-12-12
改變Orientation的三種途徑
這裡, 咱們主要理清一下: 到底有哪些設定可以改變螢幕旋轉特性. 這樣:
- 出現任何問題我們都可以從這幾個途徑中發現原因.
- 靈活應付産品經理的各種需求.
首先我們得知道:
- 當手機的重力感應打開的時候, 如果使用者旋轉手機, 系統會抛發
事件.UIDeviceOrientationDidChangeNotification
- 您可以分别設定
和Application
支援的旋轉方向.UIViewcontroller
的設定會影響整個App,Application
的設定僅僅會影響一個UIViewcontroller
(IOS5和IOS6有所不同,下面會詳細解釋).viewController
- 當
收到UIKit
事件的時候, 會根據UIDeviceOrientationDidChangeNotification
Application
的設定, 如果雙方都支援此方向, 則會自動螢幕旋轉到這個方向. 更code的表達就是, 會對兩個設定求與,得到可以支援的方向. 如果求與之後,沒有任何可支援的方向, 則會抛發UIViewcontroller
異常.UIApplicationInvalidInterfaceOrientationException
Info.plist設定
在App的Info.plist裡設定:
key | xcode name | Summary | avilable value |
---|---|---|---|
UIInterfaceOrientation | initial interface orientation | Specifies the initial orientation of the app’s user interface. | UIInterfaceOrientationPortrait, UIInterfaceOrientationPortraitUpsideDown, UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight |
UISupportedInterfaceOrientations | Supported interface orientations | Specifies the orientations that the app supports. |
在Info.plist中設定之後,這個app裡所有的
viewController
支援的自動旋轉方向都隻能是app支援的方向的子集.
UIViewController
IOS6 and above
supportedInterfaceOrientations
在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
也可以, help yourself~self.window
- 我們需要顯式的設定
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
此部落格已遷移至blog.bookbook.in,以後不再更新