29
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Swift4】特定の画面で回転を制御する方法について、サンプルを作って理解する

Last updated at Posted at 2018-11-02

仕事で実装する際にハマったので、復習のためにサンプルプロジェクトを作ってみました。

今回は特に分かりづらかったTabBarController/NavigationControllerを使う場合にフォーカスを当てて、「基本は回転を許すが、特定の画面では回転させたくない」というケースを考えてみます。

下準備

「基本は回転を許す」ので、プロジェクトのDevice Orientationは以下の通り設定します。
スクリーンショット 2018-10-31 22.56.12.png

①TabBarControllerもNavigationControllerも使わない場合

まずはシンプルな2画面があり、ほげほげVCだけは回転させたくない場合について。
スクリーンショット 2018-10-31 23.07.09.png

解決法

とても簡単で、回転させたくないViewController内に以下を追加するだけでOKです。

HogehogeViewController.swift
// 画面を回転させるかどうか
override var shouldAutorotate: Bool {
    return true
}
    
// 回転方向の指定
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .portrait
}

ちなみに、今回は拡張性を考慮して↑のように書きましたが、下記のようにシンプルにshouldAutorotatefalseを返すやり方でも同じ結果(=回転させない)を得ることができます。(shouldAutorotatetrueでないと、supportedInterfaceOrientationsプロパティは呼ばれないので書かなくてOK)

HogehogeViewController.swift
override var shouldAutorotate: Bool {
    return false
}

②TabBarControllerを使う場合

次にTabBarControllerをベースにした2画面があり、ほげほげVCだけは回転させたくない場合について。
スクリーンショット 2018-10-31 23.16.21.png
とりあえず①と同じコードをほげほげVCに書いてビルドしてみましたが、制御が効かずにほげほげVCも回転してしまいました。

supportedInterfaceOrientationsドキュメントを見てみると、

When the user changes the device orientation, the system calls this method on the root view controller or the topmost presented view controller that fills the window.

とあります。なるほど、TabBarControllerやNavigationControllerを使っているとルートのViewControllerが呼ばれるから、回転させたくないViewControllerに書くだけではダメだったんですね。

##解決法
UITabBarController+Orientation.swiftというファイルを作り、TabBarControllerを拡張します。
**ポイントはselectedViewControllerを使って、選択されたタブのViewControllerを取得し、そこで設定されたshouldAutorotatesupportedInterfaceOrientationsプロパティを取ってくること。**回転させるか否かをTabBarController側では判断せずに、各ViewControllerに委譲する形になります。

UITabBarController+Orientation.swift
extension UITabBarController {

    open override var shouldAutorotate: Bool {
        // 選択されたタブのViewControllerを取得
        if let vc = selectedViewController {
            return vc.shouldAutorotate
        } else {
            return true
        }
    }
    
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        // 選択されたタブのViewControllerを取得
        if let vc = selectedViewController {
            return vc.supportedInterfaceOrientations
        } else {
            return .allButUpsideDown
        }
    }

}

その上で、回転させたくないViewControllerに①と同じコードを書きます。

HogehogeViewController.swift
override var shouldAutorotate: Bool {
    return true
}
    
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .portrait
}

これで無事に狙った動きをさせることができました🎉

③NavigationControllerを使う場合

最後にNavigationControllerを使った画面があり、ほげほげVCだけ回転させたくない場合を見てみます。
スクリーンショット 2018-11-01 0.31.22.png

お約束的に①と同じコードをほげほげVCに直接実装してみますが、ルートのNavigationControllerが呼ばれるためにうまくいかず、ほげほげVCも回転してしまいました。

##解決法
そこで今度はNavigationController+Orientation.swiftというファイルを作り、NavigationControllerを拡張します。
**ポイントはviewControllers.lastを使って、NavigationControllerにぶら下がっているViewControllerを取得し、そこで設定されたshouldAutorotatesupportedInterfaceOrientationsプロパティを取ってくること。**TabBarControllerのときと原理は同じですね。

UINavigationController+Orientation.swift

extension UINavigationController {

    open override var shouldAutorotate: Bool {
        // NavigationControllerにぶら下がっているViewControllerを取得
        if let vc = viewControllers.last {
            return vc.shouldAutorotate
        } else {
            return true
        }
    }
    
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        // NavigationControllerにぶら下がっているViewControllerを取得
        if let vc = viewControllers.last {
            return vc.supportedInterfaceOrientations
        } else {
            return .allButUpsideDown
        }
    }

}

その上で、回転を制御したいほげほげVCに①と同じコードを追加します。

HogehogeViewController.swift
override var shouldAutorotate: Bool {
    return true
}
    
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .portrait
}

これで無事に狙った動きを得ることができました🎉ここまで来るとだいぶ回転制御がわかってきた気がします。

TabBarController/NavigationControllerの両方を使う場合も書きたかったのですが、疲れてきたのでそれはまた次回にします:wave:

参考になった記事

29
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?