開発者向け
iPhone Duo のヒンジ状態:onHingeChange と UIKit 対応
iOS 27.1 の onHingeChange や UIHingeInteraction で iPhone Duo のヒンジ状態と角度を取得し、エフェクトやゲーム操作に活用する方法と、実際に使っているゲームを紹介します。
AppleDuo 編集部公開 10分で読めます
このページの内容
iPhone Duo はヒンジを備えた初めての iPhone で、iOS 27.1 ではアプリからそのヒンジを読み取れます。デバイスが閉じているのか、少し開いているのか、完全に開いているのかがわかり、ユーザーが折りたたむ動きに合わせて正確なヒンジ角度を追うこともできます。このガイドでは、SwiftUI と UIKit の iPhone Duo ヒンジ状態 API、それを使うべき場面と使うべきでない場面を、折り目をすでに操作に変えているゲームとあわせて解説します。
詳細は、Apple のドキュメント、Apple の iPhone Duo の Tech Talk とフォーラムでの回答、そして iOS 開発者 @sarunw の投稿に基づいています。私たちはこれらの API を実機でテストしていません。iOS 27.1 と Xcode 27.1 で提供されたばかりなので、名前や動作は今後のリリースで変わる可能性があります。
iPhone Duo が報告するヒンジ状態は?
@sarunw がまとめているように、ヒンジ状態は closed、partiallyOpen、fullyOpen の3つです。Apple の Tech Talk「Leverage multiple displays and scenes on iPhone Duo」でも同じ「高レベルなヒンジの状態」が説明されており、この API が「ヒンジ角度の連続的な更新」も提供すると補足されています。
Apple のドキュメントによると、状態は「現在の角度とデバイスの向きに基づいてシステムが決定」します。つまり、判断のためのシンプルな状態と、なめらかに動かしたいもののための正確な角度の両方が手に入ります。
| 状態 | SwiftUI(DeviceHinge.Status) | UIKit(UIHinge.Status) | Apple による説明 |
|---|---|---|---|
| 閉じている | .closed | .closed | ヒンジが閉じている |
| 少し開いている | .partiallyOpen | .partiallyOpen | ヒンジが部分的に開いている |
| 完全に開いている | .fullyOpen | .fullyOpen | デバイスが許す限り開いている |
| 不明 | 記載なし | .unknown | 状態が不明 |
角度の型はフレームワークによって異なります。SwiftUI では DeviceHinge.angle は Angle です。UIKit では UIHinge.angle はラジアン単位の CGFloat です。
SwiftUI で .onHingeChange を使うには?
SwiftUI の API は onHingeChange(isEnabled:_:) で、iOS 27.1 で利用できます。アクションは以前の値と新しい値の2つの DeviceHingeContext を受け取ります。各コンテキストには DeviceHinge 型のオプショナルな hinge があり、angle と status を公開しています。
Apple のドキュメントにある次の例では、ヒンジを state に保存し、ヒンジが利用できないときはフォールバックを表示しています。
@State private var hinge: DeviceHinge? = nil
var body: some View {
VStack {
if let hinge {
AngleDisplayView(angle: hinge.angle)
StatusDisplayView(status: hinge.status)
} else {
ContentUnavailableView(
"Hinge Unavailable",
systemImage: "rectangle.split.2x1")
}
}
.onHingeChange { _, newContext in
hinge = newContext.hinge
}
}
hinge が nil ならデバイスにヒンジがないということなので、必ずこのケースを処理してください。isEnabled パラメータのデフォルトは true です。
以前の値と新しい値を使う
クロージャは両方のコンテキストを受け取るので、デバイスが閉じた瞬間のような遷移を検出できます。以下は、ドキュメント化された型だけを使って私たちが書いたスケッチです。
.onHingeChange { oldContext, newContext in
let wasClosed = oldContext.hinge?.status == .closed
let isClosed = newContext.hinge?.status == .closed
if !wasClosed && isClosed {
game.closeLid()
}
}
game.closeLid() はあなた自身のコードに置き換えてください。以前の値と新しい値を比べることで、角度だけが変わったときに同じアクションが2回実行されるのを防げます。
UIKit で UIHingeInteraction を使ってヒンジを監視するには?
UIKit では、ビューに UIHingeInteraction を追加します。そのハンドラは「ヒンジの状態が変わったとき、またはインタラクションが階層間を移動したとき」に実行されます。ヒンジの更新を提供する階層からビューが外れると、更新の hinge は nil になります。Apple のサンプルは次のとおりです。
override func viewDidLoad() {
super.viewDidLoad()
let interaction = UIHingeInteraction { [weak self] _, update in
guard let self else { return }
// `hinge` が nil の場合、インタラクションがヒンジの
// 更新を提供する階層から外れたことを示す。
guard let hinge = update.hinge else {
handleHingeUnavailable()
return
}
updateAngleDisplay(with: hinge.angle)
updateStatusDisplay(with: hinge.status)
}
view.addInteraction(interaction)
}
インタラクションには isEnabled プロパティもあります。ヒンジの情報をトレイトコレクションで探さないでください。開発者フォーラムで Apple のエンジニアは、ヒンジの姿勢に関する UITraitCollection のトレイトは存在しないと認めています。
ヒンジの状態でレイアウトを切り替えるべき?
いいえ。これが最も重要なルールです。Apple の Tech Talk では、ヒンジのデータはリアルタイムで監視されるもので、インタラクションやエフェクトを動かすのに最適であり、レイアウトには arrangement と region の API を使うべきだと説明されています。
フォーラムでは、Apple の Technology Evangelist が、最も簡単なものから最もカスタムなものまで4つのアプローチを挙げています。
NavigationSplitViewやUISplitViewControllerなどのシステムのコンテナを使う。- それで足りなければ、
ArrangementViewやUIArrangementViewControllerを試す。 - どちらもうまくいかない場合に限り、予約領域の API でビューを配置する。
onHingeChangeやヒンジのインタラクション API をレイアウトの判断に使わない。
レイアウトについての Apple のフォーラムでのガイダンスは、デバイス固有のロジックを避け、デバイスの開閉に応じて変わるサイズクラスを活用することです。これらのツールについては、iPhone Duo のサイズクラス、ArrangementView、予約領域と折り目のガイドで解説しています。折り目の分割領域はデバイスが折りたたまれているときだけ有効になるので、折り目の位置は予約領域がすでに教えてくれます。
ヒンジのイベントは、動きに反応すべきものに使います。壁紙のズームエフェクト、折り目に合わせて開くカバー、ゲームのメカニクスなどです。Apple の Tech Talk では、少し折りたたんだヒンジがワーミーバーのように働くギターアプリを作っています。
.onHingeChange { _, context in
if let hinge = context.hinge, hinge.status == .partiallyOpen {
pitchBend = calculatePitchBend(angle: hinge.angle)
}
else {
pitchBend = 0
}
}
ベンドは .partiallyOpen の状態でだけ適用され、それ以外ではリセットされます。Apple は calculatePitchBend の中身を示していないので、角度からエフェクトへのマッピングはあなた次第です。
テーブルトップモード向けにはどうデザインする?
iPhone Duo が「内側ディスプレイを自分に向けたノートパソコンのように」テーブルに置かれているとき、下半分は安定した土台になり、上半分は見やすい位置になります。Apple の Tech Talk「Design for iPhone Duo」では、メディアを上に置き、タップできるコントロールを下の安定した土台に配置することが提案されています。
ただし注意点があります。Apple は、この姿勢専用のレイアウトでも、ほかの姿勢と同じコントロールと全体的な階層をすべて保つべきだと補足しています。機能を特定の姿勢に結び付けたくないからです。アプリの場合、テーブルトップモードでコンテンツを並べ替えるのはかまいませんが、デバイスがフラットなときや閉じているときにもすべての機能が使えなければなりません。
ゲームでは姿勢そのものが楽しさになりうるので、自由度はより高くなります。それでも、フォールバックを用意しておくと役立ちます。たとえば Marbles Unhinged は App Store で、画面上のヒンジを使ってどの iPhone や iPad でもプレイできると説明しています。
ヒンジを操作に変えているゲームは?
iPhone Duo のゲームの中には、すでに折り目を入力として使っているものがいくつかあります。以下の説明は、各ゲームの App Store の掲載情報と報道に基づいています。各開発者が内部でどの API を使ったかはわかりません。
| ゲーム | ヒンジの役割 |
|---|---|
| Marbles Unhinged | 上半分を曲げると床がスロープになります。折り目が急なほど速く転がります。 |
| Toastie | スマートフォンを閉じるとトースターのふたが閉まり、開くとサンドイッチの焼け具合を確認できます。 |
| Greens: Mini-golf | ノートパソコンのように折りたたみ、下半分でパットを打つと、立てた上半分がキャディカメラになります。 |
| Battlefleet Duo | テーブルトップモードでは下の画面に自分の艦隊が、目の前に立てた画面に敵の海域が表示され、2人で向かい合って対戦できます。 |
| Duometry | MacRumors によると、デバイスを折りたたんで目標の角度に合わせ、答えを確定させます。 |
これらは API ときれいに対応しています。Toastie のふたは .closed への状態変化です。Marbles Unhinged のスロープは連続的な角度です。Greens と Battlefleet Duo はテーブルトップのレイアウトで、上半分がビューを表示し、下半分がタッチを受け付けます。Duometry には生の角度が必要です。
折り目を使うゲームは、Built for the Fold でさらに見つけられます。
まとめ:押さえておくべきポイントは?
- iPhone Duo は
closed、partiallyOpen、fullyOpenの3つのヒンジ状態と、連続的な角度を報告します。UIKit にはunknownもあります。 - SwiftUI では
.onHingeChange、UIKit ではUIHingeInteractionを使います。どちらも iOS 27.1 で追加され、ヒンジが利用できないときはnilの hinge を返します。 - SwiftUI のクロージャは以前と新しいコンテキストを受け取るので、角度の更新のたびではなく遷移に反応できます。
- レイアウトはサイズクラス、システムのコンテナ、ArrangementView、予約領域に任せます。ヒンジのデータはエフェクト、インタラクション、ゲームのメカニクスに使ってください。
- テーブルトップ向けのデザインでは、メディアを上に、コントロールを土台側に置き、ほかの姿勢で機能を隠さないようにします。
次は、予約領域のガイドでコントロールを折り目から遠ざける方法を学ぶか、Built for the Fold から上で紹介したゲームを遊んでみてください。
よくある質問
iPhone Duo のヒンジ状態にはどんなものがありますか?
closed、partiallyOpen、fullyOpen の3つです。システムが現在の角度とデバイスの向きから状態を決定します。UIKit の enum には unknown のケースもあります。
SwiftUI でヒンジの角度を読み取るには?
ビューに .onHingeChange を追加します。クロージャは以前と新しいヒンジのコンテキストを受け取り、新しいコンテキストの hinge プロパティから角度と状態を取得できます。ヒンジのないデバイスでは hinge は nil になります。
ヒンジの状態でレイアウトを変えるべきですか?
いいえ。Apple は、onHingeChange とヒンジのインタラクション API をレイアウトの判断に使うべきではないとしています。レイアウトにはサイズクラス、システムのコンテナ、ArrangementView、予約領域を使い、ヒンジのイベントはエフェクトとインタラクションに使ってください。
ヒンジ用の UITraitCollection のトレイトはありますか?
ありません。Apple のエンジニアが開発者フォーラムで、ヒンジの姿勢に関するトレイトコレクションのトレイトは存在しないと認めています。UIKit でヒンジの更新を受け取るには UIHingeInteraction を使ってください。
iPhone Duo のヒンジを操作に使っているゲームは?
例として、折りたたむと床がスロープになる Marbles Unhinged、閉じるとトースターのふたが閉まる Toastie、ノートパソコンの姿勢で下半分でパットを打つ Greens、テーブルトップモードの Battlefleet Duo、角度当てゲームの Duometry があります。
出典
- Leverage multiple displays and scenes on iPhone Duo · Apple Developer (Tech Talk)
- Design for iPhone Duo · Apple Developer (Tech Talk)
- onHingeChange(isEnabled:_:) · Apple Developer Documentation
- DeviceHinge · Apple Developer Documentation
- UIHingeInteraction · Apple Developer Documentation
- UIHinge · Apple Developer Documentation
- Strike a pose with adaptive layouts on iPhone Duo · Apple Developer (Tech Talk)
- Recommended source of truth for adapting UIKit layouts on iPhone Duo · Apple Developer Forums
- Best practice for responding to the hinge angle in SwiftUI · Apple Developer Forums
- Hinge state adaptation in UIKit: Trait collections vs. view layout callbacks · Apple Developer Forums
- What can the APIs added in iOS 27.1 for iPhone Duo do? · DevelopersIO (Classmethod)
- iPhone Duo Apps, What Changes in Your Code and What to Do With Old Ones · Pasquale Pillitteri
- The iPhone Duo Can Be a Tiny Mac, a Toaster, and a Nintendo DS · MacRumors
- There are 3 hinge states: closed, partiallyOpen, and fullyOpen · @sarunw on X
折りたたみを、アプリの一部に。
AppleDuo は iPhone Duo を本当に活かしたアプリとゲームを紹介しています。App Store へのリンクを添えて送ってください。ほかの開発者の作品も見られます。