デバイスの向きの変更を検出する方法

1. 「デバイスの向き」とは?

端末 (iPhone や iPad) が縦向きか横向きかで、レイアウトを変えたい場合など、 現在の端末の向きを知りたい場合がありますよね。

端末の縦横の向きは、オリエンテーションといいます。

縦向きを「ポートレート (portrait)」、横向きは「ランドスケープ (landscape)」といいます。

その他、端末が画面を上にしている場合もあります。このときは iOS では「フラット (flat)」といいます。

端末のオリエンテーション

ちなみに、フラットのときは地面に対して寝ている状態なので、縦向き横向きという概念はありません。

2. オリエンテーションの検出

iOS では各種の通知が定義されています。それらの通知を受け取りたい場合は、NotificationCenter に通知して欲しい通知の種類と、 どこに通知をすれば良いか、その対象を登録します。通知を受け取る対象はオブサーバーといいます。

実行中のそれぞれのアプリケーションは、デフォルトの NotificationCenter オブジェクトを持っています。 このオブジェクトに対して、ディスパッチして欲しい通知の種類を登録しておくことで、各種通知を受け取ることが可能になります。

次のコードで、オリエンテーションの変更通知を受け取るセレクタを指定することができます。

import UIKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        NotificationCenter.default.addObserver(
            self,
            selector: #selector(ViewController.orientationChanged),
            name: UIDevice.orientationDidChangeNotification,
            object: nil)
    }
    
    @objc func orientationChanged() {
      // この関数が呼ばれる
    }
}

さて、NotificationCenter を利用することで、「オリエンテーションに変更がありましたよ」という通知を受けることができました。

現在のオリエンテーションを取得するには、UIDevice.current.orientation が利用できます。 これが現在の端末のオリエンテーションを表す UIDeviceOrientation オブジェクトを保持しています。

UIDeviceOrientation オブジェクトの isPortrait プロパティや isLandscape プロパティが、現在ポートレートかランドスケープかを Bool 値で返します。

同様に isFlat はフラットであるかどうかの真偽値です。isFlat が true のとき、isPortrait と isLandscape は false を返します。

このときは、上述の通り縦横という概念はないわけですが、実際の画面の表示としてのポートレートかランドスケープかを取得するなら、 UIScreen.main.bounds を利用して縦横の状態を知ることができます。

以上をまとめると、以下のコードで向きがわかります。

@objc func orientationChanged() {
    let orientation = UIDevice.current.orientation
    let isFlat = orientation.isFlat
    var isLandscape = orientation.isLandscape
    var isPortrait = orientation.isPortrait
    
    if !isLandscape && !isPortrait {
        isPortrait = UIScreen.main.bounds.width < UIScreen.main.bounds.height;
        isLandscape = !isPortrait
    }
}

3. 動作確認してみよう

さて、上記のコードの動作確認をしてみましょう。

ラベルをひとつ配置します。

端末のオリエンテーション

このアウトレットを label として、次のコードでプロパティの値を表示させます。

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var label: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        label.text = "Ready"

        NotificationCenter.default.addObserver(
            self,
            selector: #selector(ViewController.orientationChanged),
            name: UIDevice.orientationDidChangeNotification,
            object: nil)
    }
    
    @objc func orientationChanged() {
        let orientation = UIDevice.current.orientation
        let isFlat = orientation.isFlat
        var isLandscape = orientation.isLandscape
        var isPortrait = orientation.isPortrait
        
        if !isLandscape && !isPortrait {
            isPortrait = UIScreen.main.bounds.width < UIScreen.main.bounds.height;
            isLandscape = !isPortrait
        }
        
        label.text = "flat=\(isFlat)\n"
            + "landscape=\(isLandscape)\n"
            + "portrait=\(isPortrait)"
    }
}

このプログラムを実行して、端末の向きを変えることでそれぞれのフラグがどのような値をとるか確認できます。

端末のオリエンテーション

以上で、端末の向きの変更を検出する方法と、その実際の向きの取得方法について説明しました。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Swift による iOS 開発入門