この投稿は何?
iPhoneまたはiPadのSwiftUIアプリ開発において、デバイスの姿勢変化を検出するための方法を実践します。
UIDeviceOrientation
orientation
プロパティは、以下の定数を用いてデバイスの向きを識別します。
以下の定数は、あくまでも「デバイスが物理的に向いている方向」を識別するものであり、起動中のアプリケーションUIの向きとは関係ありません。
-
unknown
デバイスの向きが特定できない状態。 -
portrait
デバイスを縦に(ホームボタンは下側に)した状態。 -
portraitUpsideDown
デバイスを縦にして、ホームボタンは上部にしたポートレートモード。 -
landscapeLeft
デバイスを縦にして、ホームボタンは右側にしたランドスケープモード。 -
landscapeRight
デバイスを縦にして、ホームボタンは左側にしたランドスケープモード。 -
faceUp
デバイスを水平にして、画面を上向きにした状態。 -
faceDown
デバイスを水平にして、画面を下向きにした状態。
UIDeviceOrientation
列挙型について、詳しい情報はこちらの開発者サイトを確認してください。
NotificationCenter(通知センター)
通知センターは、発生した通知を集めて管理する仕組みです。
オブジェクトはaddObserver(forName:object:queue:using:)
メソッドを使用して、通知(NSNotification
オブジェクト)を受け取るように通知センターに登録されます。オブジェクトは、自分自身をオブザーバーとして追加するときに「どの通知を受け取るか」を指定します。このメソッドを何度も呼び出せば、オブジェクトは「いくつかの異なる通知を受け取るオブザーバー」として自分自身を登録することができます。
実行中の各アプリに「デフォルトの通知センター」が存在し、通知を配信できるのは単一のプログラム内に限られます。
addObserver(forName:object:queue:using:)メソッド
このメソッドは、通知センターに「受け取りたい通知のエントリ」を追加します。
パラメータ
-
name
オブザーバー・ブロックに配信したい通知の名称です。
ここで指定された名称の通知のみが配信されます。
nil
の場合、通知センターは配信の基準に通知名を使用しません。 -
obj
オブザーバー・ブロックに通知を送信するオブジェクトです。
ここで指定された送信者からの通知だけを配信します。
nil
の場合、通知センターは配信の基準に送信者を使用しません。 -
queue
ブロックが実行される操作キューです。
nil
の場合、ブロックはポストしたスレッド上で同期的に実行されます。 -
block
通知受信時に実行される手続きです。
通知センターはこのブロックをコピーして、オブザーバ登録が解除されるまで強い参照で保持します。
このブロックの引数は「受信した通知」です。
返り値
オブザーバーとして動作する不明瞭オブジェクトです。
通知センターは、オブザーバの登録を解除するまでこの返り値を強い参照で保持します。
addObserver(forName:object:queue:using:)
メソッドについて、詳しい情報はこちらの開発者サイトを確認してください。
UIDeviceクラス
このクラスのインスタンスは、実際にアプリケーションが起動しているデバイス自体を示します。
UIDevice
オブジェクトを使用して、デバイスに関する情報(デバイス名、モデル名、オペレーティングシステム名とバージョンなど)を取得します。また、UIDevice
型インスタンスを使用して、デバイスの物理的な向きなどの変化を検出します。orientation
プロパティを使用して現在の向きを取得するか、orientationDidChangeNotification
を通知エントリとして登録することよって変更の通知を受け取ります。
これらの方法のいずれかを使用して向き情報を取得する前に、beginGeneratingDeviceOrientationNotifications()
メソッドを使用して通知の配信を有効にする必要があります。
デバイスの向きを追跡する必要がなくなったら、endGeneratingDeviceOrientationNotifications()
メソッドを呼び出して通知の配信を無効化します。
UIDevice
クラスについて、詳しくはこちらの開発者サイトを確認してください。
beginGeneratingDeviceOrientationNotifications()メソッド
このメソッドは、受信側が「デバイス方向の情報」を取得しようとする前に呼び出す必要があります。このメソッドは、デバイスのハードウェア機能である加速度センサーを有効にし、受信側への加速度イベントの配信を開始します。その後、受信側はこれらのイベントを使用して、デバイスの向きが変化したときに orientationDidChangeNotification
通知を送信し、orientation
プロパティを更新します。
このメソッドの呼び出しは endGeneratingDeviceOrientationNotifications()
メソッドと必ず対応づけて呼び出す必要があります。
詳しくはこちらの開発者サイトを確認してください。
endGeneratingDeviceOrientationNotifications()メソッド
このメソッドは、orientationDidChangeNotification
の通知ポストを停止し、他の場所で使用されていない場合は加速度センサーのハードウェア電源をカットできることをシステムに通知します。このメソッドを呼び出すのは、以前にbeginGeneratingDeviceOrientationNotifications()
メソッドを呼び出した後です。
詳しくはこちらの開発者サイトを確認してください。
実装
OrientationDetecterクラス
このアプリケーションのデータモデルです。
クラスの宣言においてObservableObject
プロトコルを採用しており、すべてのビュー階層から一貫性のあるデータ(信頼できる情報源)としてアクセスできます。
import SwiftUI
class OrientationDetector: ObservableObject {
@Published var currentDeviceOrientation: String = ""
private var orientationObserver: NSObjectProtocol? = nil
let notification = UIDevice.orientationDidChangeNotification
func start() {
UIDevice.current.beginGeneratingDeviceOrientationNotifications()
orientationObserver = NotificationCenter.default.addObserver(forName: notification, object: nil, queue: .main) {
[weak self] _ in
switch UIDevice.current.orientation {
case .faceUp:
self?.currentDeviceOrientation = "Face Up"
case .faceDown:
self?.currentDeviceOrientation = "Face Down"
case .portrait:
self?.currentDeviceOrientation = "Portrait"
case .portraitUpsideDown:
self?.currentDeviceOrientation = "Portrait Upside Down"
case .landscapeRight:
self?.currentDeviceOrientation = "Landscape Right"
case .landscapeLeft:
self?.currentDeviceOrientation = "Landscape Left"
case .unknown:
self?.currentDeviceOrientation = "Unknown"
default:
break }
}
}
func stop() {
if let orientationObserver = orientationObserver {
NotificationCenter.default.removeObserver(orientationObserver, name: notification, object: nil)
}
orientationObserver = nil
UIDevice.current.endGeneratingDeviceOrientationNotifications()
}
deinit {
stop()
}
}
-
start()メソッド
「デバイスの物理的な向きの変化」の検出を開始するための手続きです。 -
stop()メソッド
「デバイスの物理的な向きの変化」の検出を停止するための手続きです。
OrientationDetecterApp構造体
データモデルのOrientationDetecter
クラスを「信頼できる情報源」として初期化するために、@StateObject
属性をマークしています。
import SwiftUI
@main
struct OrientationDetecterApp: App {
@StateObject private var detecter = OrientationDetector()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(detecter)
}
}
}
ContentView構造体
アプリの画面となるビューです。
現在の「デバイスの物理的な向き」をテキスト表示します。
import SwiftUI
struct ContentView: View {
@EnvironmentObject var detecter: OrientationDetector
var body: some View {
Text("\(detecter.currentDeviceOrientation)")
.font(.title)
.onAppear(perform: detecter.start)
.onDisappear(perform: detecter.stop)
}
}
detecter
プロパティは環境オブジェクトとして宣言されています。
したがって、この値に依存しているテキストビューは、プロパティ値の変化に応じて、表示が自動的に更新されます。