天天看點

IOS Orientation, 想怎麼轉就怎麼轉~~~

IOS Orientation, 想怎麼轉就怎麼轉~~~

此博文主要針對IOS應用, 是螢幕旋轉相關問題的一個總結. 主要内容有:

IOS5,6,7不同版的适配.

強制旋轉和自動旋轉.

  • 部落格: http://www.cnblogs.com/jhzhu
  • 郵箱: [email protected]
  • 作者: 知明是以
  • 時間: 2013-12-12

改變Orientation的三種途徑

這裡, 咱們主要理清一下: 到底有哪些設定可以改變螢幕旋轉特性. 這樣:

  • 出現任何問題我們都可以從這幾個途徑中發現原因.
  • 靈活應付産品經理的各種需求.

首先我們得知道:

  1. 當手機的重力感應打開的時候, 如果使用者旋轉手機, 系統會抛發

    UIDeviceOrientationDidChangeNotification

    事件.
  2. 您可以分别設定

    Application

    UIViewcontroller

    支援的旋轉方向.

    Application

    的設定會影響整個App,

    UIViewcontroller

    的設定僅僅會影響一個

    viewController

    (IOS5和IOS6有所不同,下面會詳細解釋).
  3. UIKit

    收到

    UIDeviceOrientationDidChangeNotification

    事件的時候, 會根據

    Application

    UIViewcontroller

    的設定, 如果雙方都支援此方向, 則會自動螢幕旋轉到這個方向. 更code的表達就是, 會對兩個設定求與,得到可以支援的方向. 如果求與之後,沒有任何可支援的方向, 則會抛發

    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

支援的方向. 但是, 隻有兩種情況下此方法才會生效:

  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

此方法也屬于

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;
           

需要注意的是:

  1. 當然我們可以對目前

    viewController

    進行旋轉, 對任何

    view

    旋轉都可以.但是, 你會發現

    navigationBar

    還橫在那裡. 是以, 我們最好對一個占滿全屏的

    view

    進行旋轉. 在這裡我們旋轉的對象是

    self.navigationController.view

    , 當然

    self.window

    也可以, help yourself~
  2. 我們需要顯式的設定

    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,以後不再更新