解決 iOS6 螢幕自動旋轉(Screen Autorotate)的問題

ios 6 autorotate

螢幕自動旋轉的機制在 iOS6 中有了重大的改變,由於沒時間研究(另外一種說法就是懶~哈哈),就讓舊程式碼一直將究著使用,直到發現情況不妙了,只好還是花時間來找答案。
在 iOS5 之前的寫法如下:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
只要覆寫 UIViewController 的處理自動旋轉的方法,回傳想要的螢幕方向即可,可以用 OR ( || )來增加想要的方向,如下:
return (interfaceOrientation == UIInterfaceOrientationPortrait) || (interfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
在 iOS5 之前的做法是必須在每一個 UIViewController 中去覆寫該方法來指示要接受的螢幕方向。當然在 *-info.plist 檔中也要設定可以旋轉的方向。我覺得做起來簡單,只是麻煩了點,每個頁面都要去加那個判斷式。

這些動作在 iOS6 上完全無效,因為 iOS6 已經把該方法捨棄了,所以如果你什麼都不做,在 iOS6 上的執行結果就是你的 *-info.plist 中指定了可以轉什麼方向,就什麼方向都能轉。對於我全部都是直式,但只有某一個頁面可以轉橫的需求來說,整個 App 用起來的感覺爛透了。

最後呢,就是我找了半天終於找到正確的解決方法,我還沒能體會這個方式的好壞,但知道怎麼解決後,還滿容易的,感覺是在使用旋轉的概念上的簡化,讓整個概念更直覺。

整個設定流程如下:
  1. 設定 *-info.plist 中的 Supported interface orientations
  2. 建立自己的 UINavigationController
  3. 在自己 UINavigationController 中覆寫兩個方法:(BOOL)shouldAutorotate 及 (NSUInteger)supportedInterfaceOrientations
  4. 把 UINavigationController 加為頂層的 view
  5. 在每個頁面 UIViewController 中覆寫兩個方法:(BOOL)shouldAutorotate 及 (NSUInteger)supportedInterfaceOrientations

如果你的 App 的旋轉是所有頁面都相同,那步驟 3 即可將完成這些設定,不需要再做步驟 5 ,這應該是最大的好處,不需要每個頁面都去設定旋轉。但若某些頁面可以轉有些不行,那就和之前 iOS5 時一樣,每個頁面都要覆寫那兩個方法,只是那兩個方法的概念上不一樣了。之前是問你可以轉什麼方向,現在分成兩個問題,一個問可不可以自動旋轉,你只要回答可以或不可以;另一個則問你螢幕支援的方向,你只要回答這個頁面支援的方向就好。

流程解說

1.設定 *-info.plist 中的 Supported interface orientations

兩種做法,第一種直接去修改 plist 檔,太麻煩了!所以用第二種,在 Xcode 中選擇專案 -> TARGETS ->Summary頁籤,然後點選你想要支援的螢幕方向。如下圖:

2. 建立自己的 UINavigationController

新增一個 Objective-C class 檔案,繼承 UINavigationController,然後什麼都不用做,結束這回合(疑?)。

3. 覆寫方法

打開你的 NavigationController (.m) 貼上以下程式碼:
- (BOOL)shouldAutorotate
{
    return self.topViewController.shouldAutorotate;
}

- (NSUInteger)supportedInterfaceOrientations
{
    return self.topViewController.supportedInterfaceOrientations;
}
每個頁面都會透過 NavigationController 的這兩個方法告訴最上層的 ViewController 螢幕可不可以自動旋轉及支援的方向。

4. 把 UINavigationController 加為頂層的 view

這部份會因你使用 xib 或 storyboard 而有所不同,若用 xib 要修改 delegate 中的 didFinishLaunchingWithOptions 方法,如下:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // set initial view
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];

    navigationController = [[CustomNavigationController alloc]
                            initWithRootViewController:viewController]; // iOS 6 autorotation fix
    [navigationController setNavigationBarHidden:YES animated:NO];

    self.window = [[UIWindow alloc]
                   initWithFrame:[[UIScreen mainScreen] bounds]];

    [self.window setRootViewController:navigationController]; // iOS 6 autorotation fix
    //[self.window addSubview:navigationController.view];

    [self.window makeKeyAndVisible];

    return YES;
}
這部份我沒試,所以你要自己試看看。我用 storyboard ,做法簡單了些,完全不用加程式碼,如果你也用 storyboard 而加上以上的程式碼,會出錯。因為我的 storyboard 中已經有一個 Navigation Controller (若沒有請自行從元件庫中拉一個出來),選擇它,在 Identity Inspector 面版中修改 class 為你自定的 NavigationController ,如下圖:

5. 在每個頁面 UIViewController 中覆寫兩個方法

程式碼如下:
- (BOOL)shouldAutorotate
{
    return NO;
}

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}
第一個方法就是該頁面可不可以自動旋轉,第二個則是支援的螢幕方向。

基本上只要設定第一個方法,該螢幕就不會旋轉了,那幹嘛要設定第二個呢?我遇到的狀況是,我的頁面都是直的,當我從目前頁面進入下一個面頁時,若第二個頁面可以旋轉,並且使用者在轉成橫的方向時按下導覽列上的返回按鈕,回到的第一頁也會是轉成橫的!!而且怎麼都轉不回來,因為我們的第一個方法回答說 "不能轉",所以現在你知道為什麼要設定第二個方法了,那就是說「螢幕不能轉,而且只能直著看」,這樣就不會因為其他頁面的方向而影響了該頁面的方向。

總結

還沒去探究為什麼 iOS6 的旋轉機制要改成這樣,因為你無論如何都要建立一個 Navigation Controller ,那不需要的人怎麼辦呢?只好建立之後設為隱藏,還不太明白這個做法。新的螢幕方向常數帶有 ***Mask*** 字樣,這點要注意。原本一個只要覆寫一個方法,現在則要覆寫兩個方法,比較囉唆一點,但是至少比較清楚明白該方法的用途。

參考資料

本文網址:http://blog.tonycube.com/2013/05/ios-ios6-screen-autorotate.html
Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀

我要留言

留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。