技術ブログ

プログラミング、IT関連の記事中心

端末の回転を検知する【Swift】

■はじめに


端末が回転した時に、何か処理をしたい時ってありますよね?(多くはありませんが。。。)

例えば、カメラで写真を撮る時に、横に傾けて撮影したら横の写真が撮れる!
などなど!

そんな時に、この方法を試してみてください。

ちなみに、ここでは「基本的な端末の回転の検知方法」と「端末の回転ロックが掛かっていても端末の回転を検知する方法」
を記載します。
※後者はあまり資料がないですよね。。。

■基本的な端末の回転の検知方法


この方法では、デバイスの回転をロックすると、検知されなくなります。(コントロールパネルにある、あれです!!)

「Notification」を使った方法ですが、基本的には、この方法が一般的によく使われるのかなぁ〜?と思います。

ViewDidLoadなど、回転の検知を開始したい箇所で以下の処理を行います。
※Selectorの中は、回転が起きると呼び出しがされます。

// 回転の検知を開始
UIDevice.current.beginGeneratingDeviceOrientationNotifications()
// 回転時にセレクタのメソッドを実行する
NotificationCenter.default.addObserver(self,
                                       selector: #selector(sample),
                                       name:UIDevice.orientationDidChangeNotification,
                                       object:nil)

回転を検知した後に諸々の処理をしたい場合には、以下の実装を行います。
※メソッド名は、セレクタで指定したメソッド名にしてください。

@objc func sample() {
    // 端末の向きを判定
    switch UIDevice.current.orientation {
    case .portrait:
    // 縦の場合(ホームボタンが下に来る向き)
    case .portraitUpsideDown:
    // 反対の場合(ホームボタンが上に来る向き)
    case .landscapeLeft:
    // 左の場合(ホームボタンが右に来る向き)
    case .landscapeRight:
    // 右の場合(ホームボタンが左に来る向き)
    default:
        // 向きを取得できなかった場合には、縦の場合として処理する。
    }
}

端末の回転ロックが掛かっていても端末の回転を検知する方法

カメラなどで端末の回転ロックがかかっている場合でも回転を検知したい場合がありますよね?
その場合には、以下のクラスを用意し、利用する事で回転の検知が可能です。

import Foundation
import CoreMotion

class DeviceOrientationHelper {
    static let shared = DeviceOrientationHelper()
    private let motionManager: CMMotionManager
    private let queue: OperationQueue
    
    typealias DeviceOrientationHandler = ((_ deviceOrientation: UIDeviceOrientation) -> Void)?
    private var deviceOrientationAction: DeviceOrientationHandler?
    public var currentDeviceOrientation: UIDeviceOrientation = .portrait
    private let motionLimit: Double = 0.6
    
    init() {
        motionManager = CMMotionManager()
        motionManager.accelerometerUpdateInterval = 0.2
        queue = OperationQueue()
    }
    
    public func startDeviceOrientationNotifier(with handler: DeviceOrientationHandler) {
        self.deviceOrientationAction = handler
        motionManager.startAccelerometerUpdates(to: queue) { (data, error) in
            if let accelerometerData = data {
                var newDeviceOrientation: UIDeviceOrientation?
                
                if (accelerometerData.acceleration.x >= self.motionLimit) {
                    newDeviceOrientation = .landscapeLeft
                } else if (accelerometerData.acceleration.x <= -self.motionLimit) {
                    newDeviceOrientation = .landscapeRight
                } else if (accelerometerData.acceleration.y <= -self.motionLimit) {
                    newDeviceOrientation = .portrait
                } else if (accelerometerData.acceleration.y >= self.motionLimit) {
                    newDeviceOrientation = .portraitUpsideDown
                } else {
                    return
                }
                
                if newDeviceOrientation != self.currentDeviceOrientation {
                    self.currentDeviceOrientation = newDeviceOrientation
                    if let deviceOrientationHandler = self.deviceOrientationAction {
                        DispatchQueue.main.async {
                            deviceOrientationHandler!(self.currentDeviceOrientation)
                        }
                    }
                }
            }
        }
    }
    public func stopDeviceOrientationNotifier() {
        motionManager.stopAccelerometerUpdates()
    }
}

ちなみに、利用する時には、以下のように利用します。

まず、利用するために、フィールドに以下の変数宣言を行います。

var deviceOrientationHelper = DeviceOrientationHelper()

次に、回転の検知を開始したい場所で以下の処理を追加します。(ViewDidLoadなどかな。)

deviceOrientationHelper.startDeviceOrientationNotifier { (deviceOrientation) in
    // 回転検知後の処理
    // 「deviceOrientation」には「UIDeviceOrientation」型のデータが入っています。(回転後の向き)
    self.sample(deviceOrientation)
}

最後に、回転の検知を終了したい場所で以下の処理を追加します。

deviceOrientationHelper.stopDeviceOrientationNotifier()

回転を検知した後に諸々の処理をしたい場合には、以下の実装を行います。
※このメソッドを回転検知後の処理で呼び出します。

func sample(_ deviceOrientation: UIDeviceOrientation) {
    // 端末の向きを判定
    switch deviceOrientation {
        case .portrait:
            // 縦の場合(ホームボタンが下に来る向き)
        case .portraitUpsideDown:
            // 反対の場合(ホームボタンが上に来る向き)
        case .landscapeLeft:
            // 左の場合(ホームボタンが右に来る向き)
        case .landscapeRight:
            // 右の場合(ホームボタンが左に来る向き)
        default:
            // 向きを取得できなかった場合には、縦の場合として処理する。
    }
}