複数のViewController を作成し、それぞれ shouldAutorotate, supportedInterfaceOrientations を設定しても、ルートViewControllerしかその設定が反映されない。何故だろうと思い、調べたところ、ViewControllerはルートViewControllerとそれ以外の ViewController で動きが違うことがわかった。詳細は、次のURLを参照。
iOS 8以降、回転はViewController の View のサイズを変更することで対応するようになった。インターフェースの向きが変わると、UIKitはウィンドウのルートViewController で viewWillTransitionToSize メソッドを呼び出します。次に、そのViewController は子ビューコントローラーに通知し、メッセージをビューコントローラー階層全体に伝達します。 したがって、ルートViewController のshouldAutorotate, supportedInterfaceOrientationsは参照されるが、子のViewControllerでは、これらの値は参照されない。したがって、子のViewControllerの shouldAutorotate, supportedInterfaceOrientations を設定しても、orientationを制約することができない。viewWillTransitionToSize から回転を設定するのが正しいアプローチ思われる。
無理やり変更するのであれば、子のViewController が表示されていても、ルートViewController の shouldAutorotate, supportedInterfaceOrientations が呼び出されるので、その時に表示されている presentedViewControllerの設定値を返すようにする。
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. print("MenuViewController viewDidLoad") } override var supportedInterfaceOrientations: UIInterfaceOrientationMask { if let vc = presentedViewController { print("ViewController supportedInterfaceOrientations for Menu") return vc.supportedInterfaceOrientations } else { print("ViewController supportedInterfaceOrientation for Main") return [.portrait, .landscapeRight] } } override var shouldAutorotate: Bool { if let vc = presentedViewController { print("ViewController shouldAutorotate for Menu") return vc.shouldAutorotate } else { return true } } override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { print("ViewController preferredInterfaceOrientationForPresentation") return UIInterfaceOrientation.portrait } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { print("Main viewWillTransition") } }