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


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

  1. IOS5,6,7不同版的適配.
  2. 強制旋轉和自動旋轉.

  • 博客: http://www.cnblogs.com/jhzhu
  • 郵箱: jhzhuustc@gmail.com
  • 作者: 知明所以
  • 時間: 2013-12-12


改變Orientation的三種途徑

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

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

首先我們得知道:

  1. 當手機的重力感應打開的時候, 如果用戶旋轉手機, 系統會拋發UIDeviceOrientationDidChangeNotification 事件.
  2. 您可以分別設置ApplicationUIViewcontroller支持的旋轉方向.Application的設置會影響整個App, UIViewcontroller的設置僅僅會影響一個viewController(IOS5和IOS6有所不同,下面會詳細解釋).
  3. UIKit收到UIDeviceOrientationDidChangeNotification事件的時候, 會根據ApplicationUIViewcontroller的設置, 如果雙方都支持此方向, 則會自動屏幕旋轉到這個方向. 更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. UIInterfaceOrientationPortrait,
UIInterfaceOrientationPortraitUpsideDown,
UIInterfaceOrientationLandscapeLeft,
UIInterfaceOrientationLandscapeRight

在Info.plist中設置之后,這個app里所有的viewController支持的自動旋轉方向都只能是app支持的方向的子集.



UIViewController

IOS6 and above

supportedInterfaceOrientations

在IOS6及以上的版本中, 增添了方法UIViewController.supportedInterfaceOrientations. 此方法返回當前viewController支持的方向. 但是, 只有兩種情況下此方法才會生效:

  1. 當前viewControllerwindowrootViewController.
  2. 當前viewControllermodal模式的. 即, 此viewController是被調用presentModalViewController而顯示出來的.

在以上兩種情況中,UIViewController.supportedInterfaceOrientations方法會作用於當前viewController和所有childViewController. 以上兩種情況之外, UIKit並不會理會你的supportedInterfaceOrientations方法.

舉個栗子:

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft;
}

如果某個viewController實現了以上方法. 則, 此viewController就支持豎方向和左旋轉方向. 此viewController的所有childViewController也同時支持這兩個方向, 不多不少.

preferredInterfaceOrientationForPresentation

此方法也屬於UIViewController. 影響當前viewController的初始顯示方向. 此方法也僅有在當前viewControllerrootViewController或者是modal模式時才生效.

shouldAutorotate

此方法,用於設置當前viewController是否支持自動旋轉. 如果,你需要viewController暫停自動旋轉一小會兒. 那么可以通過這個方法來實現.同樣的, 此方法也僅有在當前viewControllerrootViewController或者是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

最后一個方法是設置UIViewtransform屬性來強制旋轉.
見下代碼:

//設置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的方法來實現.



參考資料

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM