【Xcode】アプリ画面の向きを固定する方法!デバイスの回転と縦横識別

この記事からわかること
- Xcodeでアプリの画面の向きを固定する方法
- デバイスの回転を制御する
- PortraitやLandscapeとは?
- デバイスの向き(縦/横/上向き)を取得するには?
- 画面単位で制御するには?
- UITabBarControllerやUINavigationControllerで期待通りに画面が制御できない原因
index
[open]
\ アプリをリリースしました /
環境
- Xcode:16.0
- iOS:18.0
- Swift:5.9
- macOS:Sonoma 14.6.1
iOSアプリではデフォルトの設定で端末を横にした時に画面も横向きになる仕様になっています。そのため横向き画面の対応を行うか画面の回転を制御して横向きにならないようする設定を行う必要があります。今回は「画面の回転を制御する方法」をまとめていきます。

アプリ画面の向きを固定する方法
アプリが許容する画面の向きはXcodeの「TARGETS」>「Deployment Info」>「Device Orientation(デバイスの向き)」から設定可能です。例えば縦向きのみ(横向き対応しない)ようにしたい場合はPortrait
のみにチェックを入れます。

- Portrait:縦向き
- Upside Down:逆さま(※)
- Landscape Left:左向き
- Landscape Right:右向き
ちなみに英語の意味
- Orientation(オリエンテーション):1.適応(指導) 2.方向
- Portrait(ポートレート):1.肖像画 2.印刷用紙の縦置き
- Landscape(ランドスケープ):1.風景・景色 2.印刷用紙の横置き
Upside Down(逆さま)にならない端末
デフォルトではUpside Down(逆さま)
にチェックが入っていない状態ですが、これにチェックを入れても全ての端末で画面が回転時に逆さまになるわけではありません。これは公式に以下のように記載されています。
すべての iPadOS デバイスは、この方向をサポートしています。iPad のイディオムでは、これを有効にすることをお勧めします。iPhone 12 などのホーム ボタンのない iOS デバイスでは、この方向はサポートされていません。iPhone イディオムでは、これを完全に無効にする必要があります。
つまり「iPadとホームボタンのあるiOSデバイスは逆さま対応」、「iPhone12以降のホームボタンのないiOSデバイスは逆さま非対応」のようです。
またそれでも逆さまにならず、逆さまにするためには画面がサポートする方向を制御しているsupportedInterfaceOrientations
で明示的にall
やportraitUpsideDown
を指定してUpside Down
を許容させる必要があります。(デフォルト値がiPadの場合はall
ですがiPhone場合はallButUpsideDown
になっているため)
class ViewController: UIViewController {
/// この画面がサポートする方向
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .all
}
}
iPadでのデバイスの回転
「Device Orientation(デバイスの向き)」は「iPhone Orientation」と「iPad Orientation」に分かれているのでiPadにも画面の向きを適応させたい場合は「iPad Orientation」側のチェックを設定します。
iPadは逆さま対応もしているので期待通りの動作になります。
info.plistから設定する
「アプリの画面回転の許容する方向」は「info.plist」からでも設定することが可能です。「info.plist」に設定するためのキー「Supported interface orientations (iPhone)」を指定し、値(value)には先ほどと似たような設定値を渡します。

許容する向きの設定値
- Portrait(top home button):縦向き
- Portrait(top home button):逆さま
- Landscape(left home button):左向き
- Landscape(right home button):右向き
先ほどの「Device Orientation」と「Supported interface orientations (iPhone)」はリンクしているようなのでどちらかの設定をいじるともう片方も自動で修正されます。
※ iPad:Supported interface orientations (iPad)
キー
現在の画面の向きを取得する
デバイス現在の向きをコードで取得するにはUIDevice
クラスのorientation
プロパティを参照します。
UIDevice.current.orientation
取得できるのはUIDeviceOrientation
型で値はデバイスが水平で画面が上向きのfaceUp
や不明(unknown
)などを追加した7種類定義されています。
func printOrientation() {
let orientation:UIDeviceOrientation = UIDevice.current.orientation
switch orientation{
case .unknown:
print("デバイスの向きが不明")
case .portrait:
print("デバイスの向きが縦向き")
case .portraitUpsideDown:
print("デバイスの向きが逆さま")
case .landscapeLeft:
print("デバイスの向きが左向き")
case .landscapeRight:
print("デバイスの向きが右向き")
case .faceUp:
print("デバイスが水平で画面が上向き")
case .faceDown:
print("デバイスが水平で画面が下向き")
default:
break
}
}
またデバイスの向きの変化は観測することも可能です。詳細は以下の記事を参考にしてください。
画面単位の回転制御
Xcodeからの回転制御の設定はアプリ全体に影響します。そのため特定の画面だけ横向き対応したい場合などには使用できません。画面単位ごとに回転を制御させるには先に少し登場しましたがsupportedInterfaceOrientations
をオーバーライドして許容する方向をUIInterfaceOrientationMask
型で返せばOKです。
class ViewController: UIViewController {
/// ViewControllerがサポートするインターフェイスの方向
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
}
コードから画面を回転させる
例えば任意のタイミングでコードから画面を回転させたい場合はsupportedInterfaceOrientations
の返却値を変数で保持させます。あとは任意のタイミングで切り替えるだけうまくいきそうですがこれだけでは期待通りに動作しません。サポートする画面が変化した際には明示的にsetNeedsUpdateOfSupportedInterfaceOrientations
メソッドを呼び出して通知する必要があります。
class ViewController: UIViewController {
/// 現在の画面の向き
private var currentOrientation: UIInterfaceOrientationMask = .portrait
/// ボタンタップで画面の向きをスイッチ
@IBAction func buttonTapped() {
if currentOrientation == .portrait {
currentOrientation = .landscape
} else {
currentOrientation = .portrait
}
// サポートする向きが変化したことを通知する
setNeedsUpdateOfSupportedInterfaceOrientations()
}
/// ViewControllerがサポートするインターフェイスの方向
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return currentOrientation
}
}
iOS16以前ではshouldAutorotate
というものがありこのプロパティでVCの画面の回転自体を制御していましたが今はDeprecatedになっておりsetNeedsUpdateOfSupportedInterfaceOrientations
への移行が推奨されています。
/// 画面の回転を制御(iOS16以前)
override var shouldAutorotate: Bool {
return false
}
UITabBarControllerでの画面回転制御
UITabBarController
やUINavigationController
を使用している場合は上記の方法でも期待通りに動作しません。これはsupportedInterfaceOrientations
の仕様で表示画面のルートVCの設定が反映されるためです。そのためUITabBarController
の場合は以下のようにselectedViewController
のsupportedInterfaceOrientations
を返すように実装してあげれば切り替えた画面の画面制御が反映されるようになります。
class MyTabController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if let vc = selectedViewController {
return vc.supportedInterfaceOrientations
} else {
return .allButUpsideDown
}
}
}
extension
では期待通りに動作しませんでした。
extension UITabBarController {
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
// 選択されたタブのViewControllerを取得
if let vc = selectedViewController {
return vc.supportedInterfaceOrientations
} else {
return .allButUpsideDown
}
}
}
UINavigationControllerの場合
UINavigationController
の場合はUINavigationControllerDelegate
プロトコルを使用する必要がありました。対象のVCに準拠させたらnavigationControllerSupportedInterfaceOrientations
をオーバーライドして明示的にTopViewController
のsupportedInterfaceOrientations
を指定することで期待通りに動作させることができました。
class ViewController: UIViewController {
/// 現在の画面の向き
private var currentOrientation: UIInterfaceOrientationMask = .portrait
override func viewDidLoad() {
super.viewDidLoad()
// デリゲートセット
navigationController?.delegate = self
}
/// ボタンタップで画面の向きをスイッチ
@IBAction func buttonTapped() {
if currentOrientation == .portrait {
currentOrientation = .landscape
} else {
currentOrientation = .portrait
}
// サポートする向きが変化したことを通知する
setNeedsUpdateOfSupportedInterfaceOrientations()
}
/// ViewControllerがサポートするインターフェイスの方向
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return currentOrientation
}
}
extension ViewController: UINavigationControllerDelegate {
func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask {
// TopViewControllerのsupportedInterfaceOrientationsを反映させる
return navigationController.topViewController?.supportedInterfaceOrientations ?? .allButUpsideDown
}
}
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。