swiftui-iphone-duo について
SwiftUI アプリをさまざまなウィンドウサイズや iPhone Duo のハードウェアに適応させるためのスキルです。一般的なアダプティブレイアウトを優先し、その後に折りたたみ対応や Duo 固有機能を検討します。
主な機能
- 01アダプティブレイアウトのレビュー
- 02ナビゲーションとツールバーの指針
- 03折り目を避ける配置
- 04段階別の Duo API 指針
- 05シミュレーターでの検証手順
活用シーン
- 01デバイス依存のレイアウト判定の改修
- 02マルチタスク時の幅への対応
- 03折り目付近のコントロールの確認
- 04検証済み Duo 固有動作の計画
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ flowritescode/ fwc-swiftui-skills --skill swiftui-iphone-duoインストール後、Claude Code で/swiftui-iphone-duoを入力して読み込まれたか確認します。
同梱ファイルreference.md
詳細
SwiftUI iPhone Duo
アプリに別個の「Duo バージョン」を設計しないでください。
幅や高さが連続的に変化しても機能する、適応型の SwiftUI インターフェイスから始めます。折り目、ヒンジ、セカンドディスプレイ、または縦向きのシステムバーによってエクスペリエンスが大きく向上する場合に限り、Duo 固有の動作を追加します。
目標は「このアプリを iPhone Duo に対応させる」ことではありません。目標は次のとおりです。
あらゆるサイズでこのアプリを優れたものにし、Duo 独自のハードウェアが付加価値を生む場合に活用します。
レイアウトを確認または変更する前に、ルールブックをすべて読んでください:reference.md。
使用する場面
- ユーザーがiPhone Duo、折りたたみ式 iPhone、ヒンジ、折りたたみ、または2 つのディスプレイへの対応を求めている。
- ユーザーが、マルチタスクを含む、コンパクトからワイドまでの適応型 SwiftUI レイアウトを求めている。
- コードでレイアウトの切り替えに
UIDevice、UIScreen.main(bounds または scale)、idiom、orientation、isDuo、またはisFoldedを使用している。 - 作業に縦向きのバー、ツールバー項目の順序やオーバーフロー、シートの配置、
ArrangementView、予約領域、onHingeChange/UIHingeInteraction、またはCameraCaptureAccessoryが関係する。 - プロジェクトを iOS 27.1 SDK に移行する(このビルドで全画面レイアウトと縦向きのバーが有効になります)。
関連スキル
| スキル | 読み込むタイミング |
|---|---|
| swiftui-liquid-glass(このリポジトリ) | iOS 26 以降のシステムバーとグラスのクローム |
| App Resizability(Apple、Xcode 27.1) | サイズ変更と Duo の問題を最初に確認するとき。他のエージェント向けにエクスポートするには xcrun agent skills export を使用 |
最適化の順序
- 適応型レイアウト
- 適応型ナビゲーション
- 適応型ツールバーとタブ
- 折り目に配慮した配置
- Duo 固有の配置
- ヒンジ駆動のインタラクション
- セカンドディスプレイのエクスペリエンス
段階的な API のティア
コードを書く前に、変更をすべて分類してください。Tier 2 または Tier 3 を提案する前に、必ず Tier 1 を完了してください。
Tier 1 — あらゆる環境に適用できる適応型の改善(最初に実施):
NavigationSplitView
adaptive TabView
adaptive grids
ViewThatFits
AnyLayout
size classes
container-relative sizing
system toolbars
safe-area correctness
これらは、すべての Apple プラットフォームとウインドウサイズで効果があります。
Tier 2 — Duo を考慮したレイアウト(必要な場合のみ):
reserved regions (reservedRegions(kind:options:))
ArrangementView
vertical bar tuning (axisBehavior, visibilityPriority, compression, toolbarVerticalEdge)
toolbarVerticalBehavior(.disabled), only for the documented exceptions
sheet placement (presentationPlacement)
Duo-specific safe-area handling
Tier 3 — Duo 専用のエクスペリエンス(製品にメリットがある場合のみ):
onHingeChange / UIHingeInteraction
hinge angle
CameraCaptureAccessory (scene accessory, camera apps only)
multi-scene workflows (new windows only on the inner display)
ワークフロー
コピーして進捗を管理します。
- [ ] 1. Read reference.md (start with "Platform facts")
- [ ] 2. Check the SDK: full-screen layout and vertical bars need an iOS 27.1 SDK build (Xcode 27.1)
- [ ] 3. Review screens with the decision tree
- [ ] 4. Flag red-flag patterns with file evidence
- [ ] 5. Classify each change as Tier 1 / 2 / 3
- [ ] 6. Implement Tier 1 first
- [ ] 7. Apply Tier 2/3 only when space-based layout is insufficient; gate 27.1 APIs with #available
- [ ] 8. Keep state above adaptive layout; verify continuity across widths and every pose in Device Hub
1) 既存の UI を確認する
以下の判断ツリーに沿って、SwiftUI の各画面を確認します。次の項目に印を付けてください。
- レイアウトの切り替えに使用されているデバイスの識別情報(
UIDevice、idiom、model、isDuo、isFolded) - 通常のレイアウトに使用されている
UIScreen.main(bounds、scale、保存された画面)または orientation horizontalSizeClass == .regularを「iPad」と見なしている- サイズを一度だけ(起動時または
viewIsAppearingで)読み取り、その後再読み取りしていない - 列数の固定、サイドバー幅のハードコード、根拠のない
if width > N - 状態が重複する、コンパクト表示と拡張表示で分かれたビュー階層
- 縦向きの端に移動できないカスタムツールバーやタブバー
- アイコンのないタイトル付きツールバー項目、またはシステムのオーバーフローメニューの代わりに使われているカスタムの「...」メニュー
- 折り目上に表示される重要なコンテンツ
- 階層を表示せず、単に引き伸ばしているだけのワイドレイアウト
- サイドバー、列、ナビゲーションを決めるために使用されているヒンジの角度
2) 実装またはリファクタリング
- デバイスのチェックをコンテナのスペースに置き換えます。サイズクラス、
ViewThatFits、AnyLayout、アダプティブグリッド、containerRelativeFrame/onGeometryChangeを使用します。 - コレクション → 選択 → 詳細には
NavigationSplitViewを優先します。独自に作成したサイドバーより、アダプティブなTabViewを優先します。.tabViewStyle(.sidebarAdaptable)と.defaultTabBarPlacement(.sidebar)を設定すると、内側のディスプレイでサイドバーが有効になります(iPhone では、.sidebarAdaptableのみの場合、タブバーが表示されます)。 NavigationStack/NavigationSplitView内ではシステムの.toolbar/ToolbarItem/ToolbarOverflowMenuを優先し、バーを縦向きにできるようにします。すべての項目にタイトルとアイコンを付けます。Close(.cancellationAction)を先頭に、その次に Done(.topBarPinnedTrailing)を配置し、visibilityPriorityを設定します。- ビュー階層は1つに保ちます。ナビゲーション、スクロール、選択、エディター、再生の状態はレイアウトより上位に置きます。
- 余分な幅はペイン、インスペクター、列、常時表示のナビゲーションに使い、テキスト行を長くするためには使いません。読みやすいコンテンツ幅に上限を設けます(例:
.frame(maxWidth: 700))。 - 折りたたみの影響を受けるコントロールは、その場に配置します。予約領域が現れたからといって、画面全体を再構築しないでください。
ArrangementViewは、2つの部分からなる単一の体験(プレーヤー+プレイリスト、エディター+インスペクター)にのみ使用します。アプリのナビゲーションには使用しないでください。onHingeChange/ヒンジの角度は、物理的な操作にのみ使用します。レイアウトはスペースに応じて変化します。操作はヒンジの状態に応じて変化させてもかまいません。 折りたたみに対応したレイアウトには、予約領域またはArrangementViewを使用します。innerDisplay/outerDisplayを独立したキャンバスとして扱わないでください。サポートされている外側ディスプレイのコンテンツは、カメラ撮影セッションがアクティブな間のCameraCaptureAccessoryのみです。- すべてのシートをあらゆる形態で確認し、
presentationPlacement(_:)で配置を選択します。
3) テストできない Duo の動作
Xcode 27.1 には iPhone Duo シミュレーターが含まれています(Device Hub:開く、閉じる、回転する、折りたたむ)。大半のアプリ拡張機能は実行できず、カメラもないため、カメラ撮影アクセサリーの確認には実機が必要です。
シミュレーターまたは実機で該当する動作を確認できるようになるまでは、次のようにします。
エージェントが行ってもよいこと:
- 全般的な適応性を高める
- デバイスへの依存を取り除く
- 標準的なアダプティブコンテナを採用する
- Duo 固有の API に対応できるよう、コードの境界を準備する
- 折りたたみの影響を受けそうな UI を特定する
エージェントが避けるべきこと:
- 予測したヒンジ座標をハードコーディングする
- Duo の正確な寸法を推測する
- テストしていない Duo 専用のレイアウト分岐を追加する
- 仮定に基づいて、動作している画面を再構成する
シミュレーターまたは実機で Duo 固有の動作をまだ確認できない場合は、推測に基づいて実装するのではなく、準備を優先してください。
エージェントの判断フロー
SwiftUI の画面をレビューするときは、次の順序で評価します。
-
幅が連続的に変化してもレイアウトは機能しますか?
いいえの場合:まず全体的なアダプティブレイアウトを修正します。 -
ナビゲーションを手動で切り替えて、スマートフォン用とタブレット用の実装を使い分けていますか?
はいの場合:NavigationSplitView、アダプティブなTabView、または別のシステムナビゲーションコンテナーを検討します。 -
固定幅や画面サイズを前提とした実装はありますか?
はいの場合:可能な範囲で、コンテナー相対レイアウトに置き換えます。 -
幅の広いレイアウトでは、単にコンテンツが引き伸ばされるだけですか?
はいの場合:サイドバー、詳細ペイン、インスペクター、追加の列、または補足コンテンツを検討します。 -
重要なコンテンツが折り目と重なる可能性はありますか?
はいの場合:予約領域を考慮した配置を使用します。 -
関連する2つのビューを、レイアウトに応じて手動で並べ替えていますか?
はいの場合:ArrangementView、ViewThatFits、またはAnyLayoutを評価します。 -
カスタムのツールバーやタブバーを使っていますか?または、アイコンのないツールバー項目がありますか?
はいの場合:SwiftUI のシステムバーで置き換えられるか、縦方向に適応させられるかを確認し、すべての項目にタイトルとアイコンを付けます。 -
要求されている動作は、物理的なヒンジの位置に本当に依存しますか?
いいえの場合:ヒンジ API は使用しません。
はいの場合:onHingeChange(UIKit:UIHingeInteraction)とhinge.status/hinge.angleを使用します。 -
カメラ撮影中に、外側のディスプレイに補足情報を表示すると役立ちますか?
はいの場合:CameraCaptureAccessoryを評価します。それ以外の場合は、2つ目の画面を対象にしようとしないでください。
エージェントのルール
以下は厳守してください。詳細な説明とコードはreference.mdを参照してください。
- デバイス固有のレイアウトロジックに遭遇した場合は、まず、利用可能なコンテナー領域に応じたレイアウト動作に置き換えてください。
- 手動のブレークポイントより、セマンティックなアダプティブコンテナーを優先してください。順序は、システムのナビゲーション/コンテナー → アダプティブグリッド →
ViewThatFits→ サイズクラス → 正確なジオメトリー(最後)です。 - 画面にマスター/詳細のナビゲーションが含まれる場合は、手動で構成した
HStackのサイドバーより、NavigationSplitViewを強く推奨します。 - 狭いインターフェースを際限なく引き伸ばさないでください。余ったスペースは情報密度を高めるか、補完的なペインを導入するために使ってください。
- 繰り返しコンテンツがグリッドに表示される場合は、最小アイテム幅に基づくアダプティブ列(
GridItem(.adaptive(minimum:)))を優先してください。 - 問いが「どのデバイスを使っているか」ではなく「どの配置なら収まるか」である場合は、
ViewThatFitsを使用してください。 - 個別のビュー階層を条件分岐で再構築するより、レイアウトコンテナー(
AnyLayout)の切り替えを優先してください。 - レイアウトに
UIScreen.main(bounds、scale、保存された参照)を決して使用しないでください。Appleはこれを推奨しておらず、メイン画面への参照を非推奨にする予定です。 - 重要なインタラクティブコンテンツやセマンティックなコンテンツを、アクティブな分割領域にまたがって配置しないでください。装飾的な背景やスクロールコンテンツは、通常、折り目をまたいでも問題ありません。
- 全体的な構造を変更する前に、折り目の干渉には局所的に対処してください。
- 2つのビューが1つのアダプティブな体験を構成する場合に限り、
ArrangementViewを使用してください。アプリのナビゲーションの代用にはしないでください。 - カスタムツールバーを作成する前に、そのデザインをSwiftUIのツールバーAPIで実現できないか確認してください。
- ツールバーの主要なアクションは常に表示し、利用可能なバー領域が狭くなる場合は、二次的なアクションをオーバーフローに移動してもかまいません。
- タブがアプリの主要なセクションを表し、幅広のレイアウトでナビゲーションを常時表示する利点がある場合は、SwiftUIのアダプティブサイドバーシステム(
.sidebarAdaptable+.defaultTabBarPlacement(.sidebar))を優先してください。 - セーフエリアのインセットを別の辺に手動で反映しないでください。Duoのセーフエリアは左右非対称の場合があります。
- 折り目は本の背表紙のように扱ってください。背景は折り目をまたいでもかまいませんが、精密なコンテンツはまたがせないでください。
- レイアウトはスペースに応じて変化します。インタラクションはヒンジの状態に応じて変化してもかまいません。サイドバー、列、グリッドの列数、ナビゲーションの折りたたみに
hinge.angleを使用しないでください。 - カメラ撮影中の補助コンテンツに限り、
CameraCaptureAccessoryを使用してください。メインの体験はプライマリーシーンに結び付けたままにしてください。 - レイアウトの遷移をアプリケーション状態の遷移にしてはいけません。
- すべての拡張レイアウトで、中間の幅を経てコンパクトな表示に戻るまでの自然な経路を確保してください。展開状態だからといって、幅広のアプリとは限りません。
- 利用可能な幅が広がっても、テキスト行を広くする必要があるとは限りません。
- 幅広のレイアウトでは、余白を増やすだけでなく、より有用な構造を表示してください。
- 最大限に幾何学的な配置を広げるのではなく、手の届きやすさとグループ化を優先してください。
- Tier 2またはTier 3の変更を提案する前に、必ずTier 1を完了してください。
- Duo固有の動作をシミュレーターまたはデバイスでまだ検証できない場合は、推測に基づいて実装するのではなく、準備を優先してください。
- すべてのシートをすべてのポーズで確認してください。カスタムの表示方法を構築するのではなく、配置を意図的に設定してください。
- プロジェクトのデプロイメントターゲットに合致する利用可能性チェックなしに、27.1のDuo APIを決して呼び出さないでください。
- 塗りつぶしモードの画像や動画では、狭い外側のディスプレイから幅広の内側のディスプレイまで、重要なコンテンツが常に表示されるようにしてください。
コードレビューで注意すべき点
通常のレイアウト判断にこれらが使われている場合は、問題として指摘してください。
UIScreen.main.bounds
UIScreen.main.scale
UIWindow(frame: UIScreen.main.bounds)
UIDevice.current.userInterfaceIdiom == .pad
UIDevice.current.orientation / statusBarOrientation / interfaceOrientation
if orientation == .landscape
if horizontalSizeClass == .regular { iPadLayout }
bounds.height == 844
view.bounds.width - view.safeAreaInsets.left * 2
if isIPhoneDuo
if isFolded { ... }
次の点も指摘してください。
- 大きな固定フレーム
- サイドバー幅のハードコード
- グリッド列数の固定
- 独自のツールバー(または独自の
UIToolbar/UINavigationBar/UITabBarインスタンス) - タイトルのみのツールバー項目(縦方向には配置されません)
- 独自の「...」オーバーフローメニュー
- 画面の折り目をまたいでコンテンツを直接中央揃えすること
- コンパクト状態と拡張状態の重複
- 2つの幅でしかテストされていないレイアウト
- 全幅に広がるテキストが多すぎること
- セーフエリアの外に配置されたコントロール
- 焦点位置の指定がない
.scaleAspectFill/.aspectRatio(contentMode: .fill)のヒーローメディア - ドキュメントに記載された例外以外での
toolbarVerticalBehavior(.disabled)の使用、またはビューの状態ごとの切り替え
推奨される置き換え方法は、reference.md を参照してください。
レビューチェックリスト
-
if isDuo/デバイス種別/向き/UIScreenによるレイアウト分岐がない - レイアウトが、狭い → 中間 → 広いコンテナスペースに応じて変化する
- リスト/詳細画面で、選択状態を維持する
NavigationSplitViewを使用している - グリッドでは列数を固定せず、
GridItem(.adaptive(minimum:))を使用している - 局所的なレイアウト変更には、階層を重複させず
ViewThatFitsまたはAnyLayoutを使用している - 広いレイアウトでは引き伸ばすのではなく、階層(サイドバー、詳細、インスペクタ、列)を表示する
- 読みやすさが求められるコンテンツに最大幅を設定している
- アプリが iOS 27.1 SDK でビルドされ、27.1 の API に利用可能性チェックが設定されている
- システムのツールバー/タブを使用し、項目が横方向と縦方向の両方で機能する
- すべてのツールバー項目にタイトルとアイコンがあり、最初に「閉じる」/「戻る」、次に「完了」の順で、オーバーフローの優先度が設定されている
- 重要なコントロールが(非対称の場合もある)セーフエリア内にある
- 重要なコンテンツが画面の折り目をまたいで中央揃えされていない
- 折り目/ディスプレイの変化をまたいでも状態(ナビゲーション、スクロール、選択、エディタ、再生)が維持される
- すべてのポーズでシートを確認し、必要な場合は配置を設定している
- アプリを左側に配置した場合と右側に配置した場合の両方で Split View を確認している
- ヒンジ API を物理的な操作に限って使用している
- 外側ディスプレイのコンテンツには
CameraCaptureAccessoryのみを使用し、ディスプレイを手動で指定していない - Tier 2/3 の API は Tier 1 の後に、テスト可能な場合に限って追加している
追加リソース
- 全28ルール、プラットフォームの事実、API リファレンス、変更前/変更後の例:reference.md
- Apple:iPhone Duo 向けのアプリの準備、iPhone Duo 向けのデザイン、iPhone Duo でアプリを魅力的にする3つのステップ