iPhone Duo向けの設計
概要
出典: Apple Human Interface Guidelines、「Designing for iPhone Duo」(新規ページ、2026年9月9日)。 https://developer.apple.com/design/human-interface-guidelines/designing-for-iphone-duo
核心原則: 2つのディスプレイと多くの姿勢にわたって流動的にサイズ変更する1つのアプリ。姿勢ごとにレイアウトを設計しないでください。サイズクラス(コンパクト幅 = 外側ディスプレイ、レギュラー幅 = 内側ディスプレイ)を使用し、標準システムコンポーネントに適応させます。通常のiOS HIGはすべて引き続き適用されます。
正確な文言やルールのデベロッパAPIが必要な場合は、上記のページを取得してください。
ハードウェアを1段落で
外側ディスプレイ(閉じて使用): 他のiPhoneよりも幅が広く短く、カメラは隅に固定され常に表示されます。内側ディスプレイ(開いて使用): カメラはアクティブになるまでディスプレイの背後に隠れます。中央のヒンジにより、本のような姿勢、平らな姿勢、縁に立てかける姿勢が可能です。ツールバー、タブバー、ステータスバー、Dynamic Islandは、内側ディスプレイを縦向きで使用する場合を除き、側面(垂直軸)に配置されます。
クイックリファレンスチェックリスト
レイアウト
- サイズ変更に対応するように構築: サイズクラス、レイアウトマージン、セーフエリアインセット。固定幅は使用せず、1つのディスプレイに依存するものも避けてください。
- 両方のディスプレイおよびすべての姿勢で同じ機能と状態を維持。内側ディスプレイでは、1つ追加の階層レベルを追加できます(メール: 閉じたときはリストまたはメッセージ、開いたときは両方が並んで表示)。
- 予約領域を尊重: 外側カメラ(常に、Dynamic Islandに拡大)、内側カメラ(アクティブ時のみ)、折り畳み領域(部分的に開いている時のみ)。カスタムコンポーネントには
ReservedRegion(SwiftUI)/UIView.ReservedRegion(UIKit)を使用します。 - 折り畳み時: 自己適応コンテナ(スプリットビューはペイン幅を均等にする)を優先し、偶数個のグリッド列を使用し、小さな調整を行い、劇的な再配置は避けます。
- スプリットビュー: 内側では展開され、外側では自動的に1ペインに折りたたまれます。
- アレンジメントビュー(
ArrangementView/UIArrangementViewController): プライマリとセカンダリの2つのビュー。スプリット(HStack/VStackのようなレイアウトから、並べて配置または積み重ね)またはオーバーレイ(ZStackのようなレイアウトから、重ねて配置)。ナビゲーションコンテナはそれらの外側に配置してください。
垂直コントロール
- システムのサイド配置を維持。一般的に上書きしないでください。
- コンテンツ領域は非対称: セーフエリアを使用して、サイドコントロール(スプリットビューでの別のアプリのコントロールを含む)がコンテンツを覆わないようにします。コントロールはRTL言語でも同じ側に配置されます。
- ツールバーの順序(上から下): プライマリナビゲーション(戻る、閉じる)、次に主要なアクション(完了)、その後は残りのグループをそのまま。
- オーバーフローはデフォルトで下から上へ。
ToolbarItemVisibilityPriority/UIBarButtonItemVisibilityPriorityで可視性の優先度を設定し、頻繁に使用するアクション(作成、新規メモ)やバッジ付きアイテムを表示したままにします。 - グループ項目は
ToolbarItemGroup/UIBarButtonItemGroupでグループ化。手動で固定間隔を追加しないでください。 - テキスト以外のツールバー項目にはすべて、タイトルとシンボルの両方を設定。テキストのみのボタンは最小限に抑えます(それらは水平バーに残ります)。
- スペースが限られている場合: ナビゲーション重視のビューはツールバーをオーバーフローに圧縮(デフォルト)。タスク重視のビューは代わりにタブバーを最小化します(
ToolbarVerticalCompressionBehavior/UIVerticalBarCompressionBehavior)。 - システムのオーバーフローメニューを使用。省略記号はオーバーフローのためにのみ使用します。
- 末尾以外のペインに属するコントロールは、そのペインの隣に配置(メールリストコントロールはリストの上)。
- 没入型でスクロールしないUIは、Dynamic Islandやステータスバーと干渉しない場合、全幅にわたって表示可能(電卓は5列x4行)。
ゲーム
- すべての姿勢でプレイ可能。向きの固定は問題ありませんが、画面を埋めてください。テキストとコントロールのサイズは一貫性を保ってください。レターボックス/ピラーボックスよりもアスペクト比の変更を優先。避けられない場合は、パディングをアートワークで埋めてください。
Appleのテックトークから
HIGページに明記されていない3つのDuoテックトークの詳細(111466 Design for iPhone Duo、111462 Raise the bar with iPhone Duo、111463 Strike a pose with adaptive layouts)。
設計時に考慮すべきシステム動作
- 外側ディスプレイ: コントロールは右利きの親指のリーチのために右側に配置。Dynamic IslandはLive Activityの到着に応じて垂直方向に拡大し、アプリのバーとサイドストリップを共有。スペースが不足すると、アプリの項目は自動的にオーバーフローに折りたたまれます。
- 部分的に折り畳んだ状態(本): テキスト、画像、インタラクティブ要素はカーブから遠ざけられます。縦向きで折り畳んだ場合、インタラクティブ要素は下半分に移動します。
- スプリットビューマルチタスキング: ホームジェスチャを使用してアプリをサイドにドラッグすると、50/50の均等な分割が得られます。各アプリのコントロールは外側の端に配置されます。
- ピクチャインピクチャは上部にピン留め可能。下のアプリは垂直方向にサイズ変更され、折り畳んだときビデオは画面の半分を埋めます。
- シート: 外側ディスプレイでは、シートツールバーは垂直に配置。内側ディスプレイでは、シートは中央に配置され、水平バーが付きます。折り畳んだとき、シートは折り目からスライドオフします。
preferredPlacementを使用すると、左に配置されたシートには垂直バーがなく、右に配置されたシートには垂直バーが付きます。 - 組み込みの折り目回避(シート、アラート、メニュー、ツールバーボタンなど)は、インタラクティブ要素を折り目から遠ざけます。スクロール可能なコンテンツは折り目を回避する必要はありません。
垂直バーへのオプトイン
- 最新のSDKでリビルド。
- ナビゲーションコンテナが所有するバーを使用: SwiftUIの
NavigationStack、NavigationSplitView、TabView上の.toolbar。UINavigationController/UITabBarController内のビューコントローラに設定されたUIKit項目。カスタムUIToolbar/UINavigationBar/UITabBarのコンテンツは移動されません。
- ディスプレイの端にあるコンテナのみが垂直に配置されます。スプリットビューでは詳細列のみが対象。インスペクタは独自の垂直バーを取得しません。
- マッピング: 上部ツールバーの項目はストリップの上部に、下部の項目は下部に移動し、タブバーは下部に揃えられたまま。フレキシブルスペーサーは高さゼロ、固定スペーサーはサイズを維持。
- 戻る/閉じる: ナビゲーションコントローラーで自動。カスタムのものは
.cancellationAction(SwiftUI)またはleftItemSupplementsBackButton = falseを設定した先頭項目(UIKit)を使用。主要なアクションはtopBarPinnedTrailing(SwiftUI)またはpinnedTrailingGroup(UIKit)を使用。
垂直になるもの、水平のままのもの
- 垂直バーは固定幅とフレキシブルな高さを持つため、シンボルのみの項目に適しています。アイコンがある項目は垂直に。テキストのみの項目(編集、セグメント化コントロール、幅の広いテキストボタン)は水平のナビゲーションバーに残ります。
- 新しいAxisBehavior APIで上書き: シンボルとテキストの間で変化する項目(カスタムの選択など。システムの編集ボタンはこれを自動処理)には水平専用を、垂直フォームを持つカスタムビュー(例: コンパス)には垂直優先を使用。
- テキストとシンボルの項目を、バッジ(iOS 26のバッジAPI)付きのシンボルのみに変換(例: 受信箱のカウント)。実際の情報を伝える場合(カートの合計)はテキストを保持。
- キーボードアクセサリバーはキーボードに付いたまま。
- カスタムビュー: 固定幅に合わせるか、垂直レイアウトを提供。
toolbarVerticalEdge(環境値またはトレイト)を読み取ります。バーが垂直になれない場合はnilになります。 - 垂直バーにはデフォルトでスクロールエッジ効果はありません。「透明度を下げる」がオンの場合にのみ背景を取得するため、カスタムコンテンツはどちらでも読みやすい状態を維持する必要があります。
- オプトアウトするには(電卓のようなシングルページで下部が重いアプリ、または閉じるボタンのみのシート)、
toolbarVerticalBehavior/preferredVerticalBarBehaviorを使用。垂直バーのないシートはカメラのすぐ手前で止まります。 - ビューごとの圧縮:
toolbarCompressionBehavior。可視性の優先度は高、低、またはカスタムに設定可能。最初にグループごとに設定し、次に項目ごとに設定します。
レイアウトパターン
- 外側ディスプレイ: ほとんどのコンテンツは、水平セーフエリアインセットに合わせることで、コントロールの背後に隠れないようにオフセットが必要。没入型でスクロールしないUIで、バーの下に対話要素がない場合にのみ、ディスプレイ全体を中央に配置。混合アプローチは、全幅の背景とインセットされたスクロールコンテンツを使用し、すべてのインタラクティブ要素をインセット領域内に配置します。
- 内側ディスプレイ(単に引き伸ばされた電話アプリにならないように): スプリットビュー、幅が広くなると2列になる積み重ねレイアウト(ミュージック)、または情報密度の高いアプリではタブバーをサイドバーとして表示(ヘルスケア)。
- オプションのテーブル(ラップトップ)姿勢レイアウト: メディアを上部、コントロールを安定した下半分に配置。すべてのコントロールと同じ階層を維持する必要があります。
- 置き換え: 要素を予約領域から、その目的に適した領域に移動します。スコープを選択: 要素が単独で存在する場合は単独で、関連する要素は一緒に移動し、元の場所から遠くに移動しないでください。本の姿勢では、アラートはトレーリング側(閉じたときに再表示される場所の近く)に移動。テーブル姿勢では、一見できるコンテンツは上部、タップ可能なコントロールは下部。検索は検索対象のビューの上に配置。グリッドの場合は、外側のマージンを維持し、ヒンジのガターを広げます(フィットネス)。
- システムのスプリットビューは、折り畳んだとき50/50に均等化されます(リマインダー)。
予約領域API
- SwiftUI:
GeometryProxyのreservedRegion(GeometryReaderまたはonGeometryChangeから)。UIKit:UIViewのreservedRegion。レイアウトには.frameを使用。 - 2種類あります。分割領域(折り目)は折り畳んだときのみアクティブで、平らなときは幅がゼロになります。遮蔽領域(内側FaceTimeカメラ)はカメラがオンのときのみアクティブ。
- アクティブな領域はデフォルトで返されます。
includeInactiveを使用して事前計画(例: 分割領域が存在する場合は常に偶数の列数を選択)。 - カメラ中心のアプリの場合、主要なコンテンツとコントロールを内側カメラから遠ざけてください。
- 折り畳み状態をインタラクション入力として扱うことについては、このスキルには含まれていないトーク「Leverage multiple displays and scenes on iPhone Duo」で説明されています。
アレンジメントビュー(iOS 27.1)
- SwiftUI:
NavigationStack内のArrangementView(primary, secondary)。.arrangementViewStyle(.split)(デフォルト)または.overlayでスタイル設定。.split.axes(...)を使用して分割方向を制限。主軸に沿って分割できない場合は、プライマリビューのみを表示。 - UIKit: ナビゲーションコントローラのルートとして
UIArrangementViewController、UISplitArrangementを使用してupdateArrangement。 - オーバーレイ: 平らなときは積み重ね、折り畳んだときは並べて配置。
overlayArrangementZIndex(SwiftUI)、またはstate(for:)→.zIndex(UIKit)を読み取り、折りたたまれたセカンダリビューと展開されたセカンダリビューを切り替えます。 - 選択: 既存のパターンに従う(HStack/VStackはスプリット、ZStackはオーバーレイ)。それ以外の場合は、前景/背景の関係でスクロール可能なコンテンツの一部が隠れても問題ない場合はオーバーレイ(アクセシビリティリーダー)、どちらのビューも隠れてはいけないメイン/詳細の場合はスプリット(ポッドキャストのトランスクリプト)を使用。
- ナビゲーションコンテナをArrangementView内に配置しないでください。また、ArrangementViewを
List/ScrollView内に配置しないでください。
準備監査(トークから)
- 最新のSDKでリビルド。
- バーを監査: システムコンテナ、項目の順序、タイトル付きシンボル。
- カスタム項目を垂直対応にする。
- オーバーフローの優先度を設定。
- 中央揃えのレイアウトを監査: それぞれを2列にするか、置き換えるか、ArrangementViewを使用する必要がありますか?
- 手動レイアウトの高優先度コントロールには予約領域APIを採用。
Duoクラフトレイヤー(apple-designスキルより)
HIGは何が適応するかを示します。このセクションでは、Appleの流体インターフェースおよび設計原則ガイダンス(WWDC Designing Fluid Interfaces、Principles of Great Design)を、Duo上でどのように感じられるべきかに適用します。これらは適用された原則であり、HIGルールではありません。完全なモーションツールキット(投影、ラバーバンディング、速度ハンドオフ)については、Emil Kowalskiのapple-designスキル(emilkowalski/skillsから)も読み込み、そのWeb例をSwiftUI/UIKitに変換してください。
折り畳みとサイズ変更のモーション
- 折り畳みは継続的なユーザー駆動のジェスチャーです。それに続くレイアウト変更(ペイン幅の均等化、グリッドの再フロー、コンテンツの折り畳み領域からの移動)は、ヒンジをスムーズに追跡し、割り込み可能でなければなりません: ユーザーは折り畳みの途中で停止または反転できるため、常に現在の画面の値からアニメーション化し、最終状態にスナップしないでください。
- 再フローには臨界減衰バネを使用(SwiftUIの
.spring(duration: 0.4, bounce: 0)または.smooth、UIKitのUIView.animate(springDuration:bounce:)でbounce: 0)。バウンスなし: ユーザーは何もフリックしていないため、オーバーシュートは壊れているように見えます。 - ディスプレイ間の空間的一貫性: デバイスを開くとき、ユーザーが外側ディスプレイで見ていた項目がアンカーとして残ります(メールの開いたメールは新しい画面ではなく、トレーリングペインになります)。スクロール位置と選択状態を維持。追加の階層レベルはその横に表示されます。
- 再配置よりも小さな調整(HIG)は「変更の方向にヒントを与える」という同じルールです: 要素は新しい場所にテレポートするのではなく、目に見えてスライドする必要があります。
マテリアルレイヤーとしてのサイドコントロール
- サイドツールバーとタブバーは、デフォルトではスクロールエッジ効果や背景なしでコンテンツの上にフロートします(テックトークによる)。ハードディバイダーや独自の背景を追加しないでください。セーフエリアインセットを使用して、コンテンツがバーの背後に隠れないようにします。
- バーに配置されたカスタムビューは、その背後をスクロールするもの、および「透明度を下げる」で表示される不透明な背景の上でも読みやすい状態を維持する必要があります。
Duoにマッピングされた原則
- 親しみやすさ: 垂直バーの配置を上書きしないでください。これはプラットフォームの新しい筋肉記憶です。
- グループ化とマッピング: コントロールは影響を与えるペインの隣に配置(メールリストコントロールはリストの上)。
- 道案内: すべての姿勢で、ユーザーは「自分はどこにいるのか、どうやって戻るのか」に答えられる必要があります。戻る/閉じるは常に垂直軸の上部にあります。
- 柔軟性: 1つのアダプティブレイアウト、Dynamic Typeはそれに応じて拡大縮小。サイドバーが存在する、細くて高い外側ディスプレイで最大のテキストサイズをテストします。
- 応答性: 姿勢の変更が入力をブロックしてはいけません。折り畳み中のタップはまだ着弾する必要があります。
アクセシビリティ
- 「視差効果を減らす」がオンの場合、再フローのスライド/バネを短いクロスフェードに置き換え。
- 「透明度を下げる」がオンの場合、サイドバーは不透明になります。
- 折り畳み中に動く大きなサーフェス: モーションを短く保ち、大きな明るさのジャンプを避けます。
よくある間違い
| 間違い | 修正 |
|---|---|
| 姿勢ごとのカスタムレイアウト | サイズクラスとリサイズ可能なレイアウト |
| 機能や状態を非表示にする | 両方のディスプレイとすべての姿勢で同じ機能と状態 |
| 予約領域の無視 | ReservedRegion APIを採用 |
| 折り畳み時のドラマチックな再配置 | 小さな調整、滑らかなアニメーション |
| ツールバーのテキスト項目を強制的に垂直に | AxisBehaviorを使用するか、テキスト項目は水平のまま |
| 垂直バーへのカスタム背景の追加 | システムのデフォルト(透明)を尊重 |
| 手動の固定スペーサー | ToolbarItemGroupを使用 |
| ツールバー項目のタイトルなし | すべての項目にタイトルとシンボルを追加 |
| オーバーフロー優先度を設定しない | 頻繁なアクションに高い優先度を設定 |
| スプリットビュー内のナビゲーションコンテナ | ArrangementView外で使用 |
| 折り畳みアニメーションでバウンスを使用 | 臨界減衰バネ(bounce: 0) |
| アクセシビリティ設定のテスト不足 | 「視差効果を減らす」および「透明度を下げる」でテスト |