開発者向け
iPhone Duo のタブバーと NavigationSplitView 対応
iPhone Duo でタブバーが縦向きバーに移動する仕組み、NavigationSplitView で縦向きバーが付く列、インスペクタが横向きのままの理由、マージンの扱いを解説します。
AppleDuo 編集部公開 15分で読めます
このページの内容
TabView や UITabBarController を使ったアプリを iPhone Duo で実行すると、iPhone Duo のタブバーはもう画面の下部に沿った1列ではありません。画面の横に移動し、ナビゲーションやツールバーのアイテムがある縦向きバーに収まります。スプリットビューも変わります。NavigationSplitView では縦向きバーが付くのは1つの列だけで、展開したインスペクタには付きません。
このガイドでは、タブバー、スプリットビューの列、インスペクタがどうなるか、スペースが足りないときにどちらのバーを譲らせるか、そして左右対称ではなくなったバーの隣にコンテンツをどう配置するかを解説します。シンボル、オーバーフロー、オプトアウトといった縦向きバー全般のルールについては、iPhone Duo の縦向きツールバーのガイドをご覧ください。ここでの内容はすべて、Apple の Tech Talk「Raise the bar with iPhone Duo」、Apple のドキュメント、Apple のフォーラムでの DTS のまとめ、@sarunw の投稿に基づいています。これらの API は iOS 27.0 と 27.1 で新たに追加されたもので、リリース間で詳細が変わる可能性があります。
iPhone Duo ではタブバーも横に移動する?
移動します。Apple のトーク「Prepare your app for iPhone Duo」によると、TabView と UITabBarController はすべての姿勢に適応し、タブは内側と外側のディスプレイに表示され、「適切な場面では縦に配置」されます。つまり、他のバーと同じ状況、すなわち外側ディスプレイと、横向きの内側ディスプレイです。内側ディスプレイの縦向きでは、バーは横向きのままです。
Apple は、ナビゲーション、ツールバー、タブバーのコントロールが1つの領域を共有すると説明し、そのレイアウトを90度回転させて縦のスタックにしたものを想像するよう勧めています。Apple の例では3つの組み合わせがすべて示されています。メモはツールバー、時計はタブバー、フィットネスはその両方を使っています。@sarunw の説明では、横に並んだタブは「バーの下部付近で縦のスタックになります」。ツールバーのアイテムはバーの上部を占め、Apple のガイダンスでは、そこに「戻る」「閉じる」や Done のような目立つアクションを置くとされています。
これは、iOS 27.1 SDK でビルドし、システムのコンテナを使うことで得られます。iPhone Duo のグループラボについての Apple DTS エンジニアのまとめでは、この適応は単独のバーではなく、TabView と UITabBarController というコンテナに結び付いていると明言されています。カスタムのタブバーや、自分で配置した UITabBar は移動しません。どうしても残す必要がある場合は、縦向きツールバーのガイドで説明しているように、環境値 toolbarVerticalEdge または verticalBarEdge トレイトを使って配置してください。
縦向きになるバーのアイテムと、横向きのままのアイテムは?
タブは、バーの他の部分と同じアイテムのルールに従います。Apple の Tech Talk では、「戻る」や共有ボタンのようなアイコンのあるアイテムは軸が縦向きに変わり、編集ボタンのようなテキストのみのアイテムは横向きの軸に留まると説明されています。@sarunw のまとめも同じで、「戻る」や共有のようなアイコンのアイテムは縦向きバーに移動し、Edit のようなテキストのみのアイテムは横向きのままです。
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button("Share", systemImage: "square.and.arrow.up") { share() }
}
ToolbarItem(placement: .secondaryAction) {
Button("Edit") { isEditing.toggle() }
}
}
このサンプルでは、Share にはシンボルがあるので縦向きにできます。Edit にはタイトルしかないので、横向きのままです。Edit を縦向きバーに入れたい場合は、シンボルも与えてください。DTS のまとめによると、システムはタイトルのみのアイテムを縦向きに表示しません。システムはオーバーフローメニューでタイトルを表示するので、すべてのアイテムにタイトルを残しておきましょう。
タブについても、各 Tab に同じことが当てはまります。Tab("Recents", systemImage: "clock") のように、タイトルと systemImage を与えてください。バッジは、テキストを増やさずに情報を残すよい方法です。Apple のトークでは、テキストとシンボルを持つアイテムを、SwiftUI の .badge(7) や UIKit の item.badge = .count(7) を使ったシンボルに置き換えています。
タブバーとツールバーのどちらを先に圧縮するかを選ぶには?
タブバーとツールバーが縦向きバーを共有すると、特に外側ディスプレイの横向きでは、どちらかが先にスペースを使い果たします。Apple のトークでは、2種類のアプリに対する2つのデフォルトが説明されています。Podcast のようなナビゲーション中心のビューでは、主要な移動先にアクセスできるようツールバーが先に圧縮されます。これがデフォルトです。ゲームアプリのようなタスク中心のビューでは、頻繁に使うアクションを表示し続けるためにタブバーが先に圧縮されます。譲った側のバーはオーバーフローボタンにまとめられます。
iOS 27.1 の新機能である SwiftUI の toolbarVerticalCompressionBehavior(_:) は、ビューごとにこの優先設定を指定します。UIKit では、同じく iOS 27.1 の新機能である verticalBarCompressionBehavior をビューコントローラのナビゲーションアイテムに設定します。
TabView {
Tab("Recents", systemImage: "clock") {
NavigationStack {
RecentsView()
.toolbar {
Button("Up", systemImage: "chevron.up") { moveUp() }
Button("Down", systemImage: "chevron.down") { moveDown() }
}
.toolbarVerticalCompressionBehavior(.prefersToolbarItems)
}
}
}
navigationItem.verticalBarCompressionBehavior = .prefersBarItems
1つ目のサンプルは Apple のドキュメントに沿ったもので、ドキュメントではツールバーのアイテムを優先する例としてファイルのような生産性アプリが使われています。2つ目は Tech Talk で紹介されている UIKit の書き方です。値はフレームワークによって少し異なります。
| 優先設定 | SwiftUI | UIKit |
|---|---|---|
| システムに任せる(デフォルト) | .automatic | .automatic |
| ツールバーのアイテムを表示し続ける | .prefersToolbarItems | .prefersBarItems |
| タブバーを表示し続ける | .prefersTabBar | .prefersTabBar |
ツールバーの中でも、優先度は引き続き重要です。@sarunw が指摘しているように、重要なアイテムには .visibilityPriority(.high) を設定し、限られたスペースでも表示し続けるようにしましょう。順序とオーバーフローについては、縦向きツールバーのガイドで詳しく解説しています。
内側ディスプレイでタブバーの代わりにサイドバーを表示できる?
できます。iPhone では、iPadOS のようにサイドバーに適応するのではなく、iOS はタブバーを表示します。iPhone Duo の内側ディスプレイでは、より充実したナビゲーションのためにサイドバーを選択できます。SwiftUI では、sidebarAdaptable スタイルと一緒に defaultTabBarPlacement(_:) を使います。UIKit では、sidebar の preferredPlacement を設定します。どちらも iOS 27.0 から利用できます。
TabView {
Tab("Home", systemImage: "house") { HomeView() }
Tab("Favorites", systemImage: "star") { FavoritesView() }
}
.tabViewStyle(.sidebarAdaptable)
.defaultTabBarPlacement(.sidebar)
tabBarController.sidebar.preferredPlacement = .sidebar
Apple のドキュメントによると、defaultTabBarPlacement(_:) は、iPhone のようにスタイルがサイドバーかタブバーのどちらかに解決される場面で適用され、バーが変形できる iPadOS では効果がありません。UIKit では、automatic の配置は iOS ではタブバーに解決されます。
TabView についてもう1つ。toolbarVerticalBehavior(.disabled) で縦向きバーをオプトアウトした場合、Apple のドキュメントによると、TabView は選択中のタブからこの動作を解決します。タブを切り替えたときにレイアウトが跳ねないよう、タブ間で設定を揃えておきましょう。
iPhone Duo で NavigationSplitView のどの列に縦向きバーが付く?
詳細列だけです。Apple のルールでは、ツールバーのアイテムが縦向きに移動できるのはコンテナがディスプレイの端に沿っている場合だけなので、スプリットビューでは詳細列だけが対象になり、その他の列のアイテムは横向きのままです。@sarunw はこう要約しています。「バーが縦向きになるのは、そのコンテナがディスプレイの端に沿っている場合だけです。」
DTS のまとめでは、内側ディスプレイについて具体的に説明されています。システムはサイドバー列やコンテンツ列のバーを横向きに、詳細列のバーを trailing 側の端に縦向きに表示します。iPhone Duo を閉じると、NavigationSplitView と UISplitViewController は1つのスタックによるナビゲーションに折りたたまれ、開くと列を並べるか重ねて表示します。
| 状況 | サイドバー列とコンテンツ列 | 詳細列 | 展開したインスペクタ |
|---|---|---|---|
| 内側ディスプレイ、横向き | 横向きのバー | 縦向きバー、trailing 側の端 | 横向きのアイテム |
| 内側ディスプレイ、縦向き | 横向きのバー | 横向きのバー | 横向きのアイテム |
| 外側ディスプレイ(閉じた状態) | 1つのスタックに折りたたみ | 1つのスタックに折りたたみ | シートとして表示 |
外側ディスプレイの行は、Apple の折りたたみの動作とインスペクタのドキュメントに基づいています。スタックはその後、外側ディスプレイの縦向きバーのルールに従います。スプリットビューでは最も trailing 側の列が toolbarVerticalBehavior も決めるので、オプトアウトは詳細列のビューに指定してください。
NavigationSplitView {
SidebarList(selection: $selection)
} detail: {
DetailView(item: selection)
.toolbar {
Button("Share", systemImage: "square.and.arrow.up") { share() }
}
.inspector(isPresented: $showsInspector) {
InspectorView(item: selection)
}
}
ここでは Share ボタンが詳細列にあるので、縦向きにできるのはこのアイテムです。サイドバーのリストに付けたツールバーのアイテムは横向きのままです。
展開したインスペクタのアイテムが横向きのままなのはなぜ?
Apple の Tech Talk によると、詳細列にはすでに縦向きバーがあるため、混乱を避けるために、インスペクタには展開時に専用のバーが与えられません。@sarunw の言い方では、詳細列にはすでに縦向きバーがあり、「2本目があると競合してしまう」のです。
DTS のまとめでは、これがどう組み合わさるかも補足されています。内側ディスプレイでは、NavigationSplitView でビルドし、詳細ビューに inspector(isPresented:content:) を適用すると、サイドバーとインスペクタを共存させられます。インスペクタはバーを追加するのではなく、詳細列の trailing 側のレイアウトと連携します。Apple のインスペクタのドキュメントには、水平方向が regular のサイズクラスでは trailing 側の列として表示され、compact のサイズクラスではシートに適応するとも書かれています。DTS の回答によると、外側ディスプレイやスプリットビューが折りたたまれたときには、シートとして表示されます。
実際には、インスペクタのコントロールは横向きのバー向けに、必要に応じてタイトル付きで設計してください。インスペクタにしかないアクションを縦向きバーに頼らないようにしましょう。
NavigationSplitView の各列はどのサイズクラスを返す?
iPhone Duo でのウインドウのサイズクラスは十分に文書化されています。向きにかかわらず、外側ディスプレイでは幅が compact、内側ディスプレイでは幅と高さが regular です。表の全体は iPhone Duo のサイズクラスのガイドにあります。列については別の話です。@sarunw は iPhone Duo での NavigationSplitView の各列のサイズクラスの表を公開しており、そこから読み取るべきなのは、列がウインドウと同じ値を返すとは限らないということです。
ですから、サイズクラスはウインドウやルートのレベルではなく、レイアウトを行う列の中で読み取りましょう。
struct DetailView: View {
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
let item: Item?
var body: some View {
if horizontalSizeClass == .regular {
WideDetailLayout(item: item)
} else {
CompactDetailLayout(item: item)
}
}
}
環境値を DetailView の中で読み取っているので、列自身のトレイトが反映されます。Apple のトーク「Strike a pose」では、内側ディスプレイに関連する細かな点も紹介されています。リマインダーのようなスプリットビューのアプリでは、システムが列の幅を均等な50/50の分割に調整して、両方の列を表示し続けます。列ではなく自分でペインを構築する場合は、ArrangementView が同じように各ペインに独自のサイズクラスを与えます。
パディングを決め打ちせずに縦向きバーの隣にコンテンツを配置するには?
詳細列の片側に縦向きバーがあり、反対側にサイドバーがある場合、左右のマージンは同じではありません。@sarunw の助言は簡潔です。パディングはデバイスや向きによって対称とは限らないので決め打ちせず、layoutMarginsGuide を使うこと。Apple の Tech Talk によると、iPhone Duo のレイアウトマージンはセーフエリアと同じく非対称なので、前面のコンテンツを縦に並んだボタンに近づけつつ、反対側のマージンは維持できます。
NSLayoutConstraint.activate([
headerView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
headerView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor),
headerView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor)
])
layoutMarginsGuide に固定すると、各端のマージンが個別に反映されるので、16 や 20 ポイントをハードコードする必要はありません。バーもセーフエリアの外側に配置されます。Apple によると、縦向きバーが提供するのは上下ではなく leading と trailing のインセットです。SwiftUI での書き方とインセットのルールの全体については、iPhone Duo のセーフエリアとコンテンツマージンをご覧ください。
まとめ
TabViewまたはUITabBarControllerを使いましょう。タブは縦向きバーの下部付近にスタックとして移動します。カスタムのタブバーは移動しません。- すべてのタブとツールバーのアイテムにシンボルとタイトルを与えましょう。アイコンのあるアイテムは縦向きになり、テキストのみのアイテムは横向きのままです。
- どちらのバーを先に圧縮するかは
toolbarVerticalCompressionBehaviorまたはverticalBarCompressionBehaviorで選びます。デフォルトではツールバーが先です。 NavigationSplitViewでは詳細列だけに縦向きバーが付き、展開したインスペクタのアイテムは横向きのままです。- サイズクラスは各列の中で読み取り、左右が同じパディングだと決め打ちせずにコンテンツを
layoutMarginsGuideに固定しましょう。
次は、縦向きツールバーのガイドで縦向きバーの残りのルールを確認し、Built for the fold で他のアプリやゲームがこのデバイスをどう活かしているかをご覧ください。
よくある質問
iPhone Duo ではタブバーも移動しますか?
はい。iOS 27.1 SDK でビルドし、TabView または UITabBarController を使っているアプリでは、適切な場面でタブが縦に配置され、ナビゲーションやツールバーのアイテムと縦向きバーを共有します。カスタムのタブバーや単独の UITabBar インスタンスは移動しません。
iPhone Duo で NavigationSplitView のどの列に縦向きバーが付きますか?
詳細列だけです。ディスプレイの端に沿っているのが詳細列だからです。内側ディスプレイでは、サイドバー列とコンテンツ列は横向きのバーのままで、詳細列のバーは trailing 側の端で縦向きになります。
iPhone Duo でインスペクタのアイテムが横向きのままなのはなぜ?
詳細列にはすでに縦向きバーがあり、その隣に2本目があると互いに競合してしまうからです。Apple は展開したインスペクタに専用の縦向きバーを与えないことにしたため、そのアイテムは横向きのままです。
縦向きバーのスペースが足りないときにタブを表示し続けるには?
SwiftUI では toolbarVerticalCompressionBehavior(.prefersTabBar) を適用し、UIKit ではナビゲーションアイテムの verticalBarCompressionBehavior を .prefersTabBar に設定します。デフォルトでは、主要な移動先にアクセスできるようツールバーが先に圧縮されます。
iPhone Duo の内側ディスプレイで、タブバーの代わりにサイドバーを表示できますか?
できます。SwiftUI では sidebarAdaptable のタブビュースタイルと defaultTabBarPlacement(.sidebar) を使います。UIKit では、タブバーコントローラの sidebar の preferredPlacement を .sidebar に設定します。どちらも iOS 27.0 から利用できます。
出典
- Raise the bar with iPhone Duo · Apple Developer
- Prepare your app for iPhone Duo · Apple Developer
- Strike a pose with adaptive layouts on iPhone Duo · Apple Developer
- toolbarVerticalCompressionBehavior(_:) · Apple Developer Documentation
- verticalBarCompressionBehavior · Apple Developer Documentation
- toolbarVerticalBehavior(_:) · Apple Developer Documentation
- defaultTabBarPlacement(_:) · Apple Developer Documentation
- UITabBarController.Sidebar preferredPlacement · Apple Developer Documentation
- inspector(isPresented:content:) · Apple Developer Documentation
- layoutMarginsGuide · Apple Developer Documentation
- A Summary of the iPhone Duo Group Lab · Apple Developer Forums
- Tab bars move to the side on iPhone Duo too · @sarunw on X
- Items with an icon move to the vertical bar; text-only items stay horizontal · @sarunw on X
- A bar only goes vertical when its container sits along the display edge · @sarunw on X
- An expanded inspector keeps its items horizontal · @sarunw on X
- Size classes of each column in NavigationSplitView on iPhone Duo · @sarunw on X
- Set .visibilityPriority(.high) for important items · @sarunw on X
- Don't assume padding; use layoutMarginsGuide · @sarunw on X
- What can the APIs added in iOS 27.1 for iPhone Duo do? · DevelopersIO (Classmethod)
折りたたみを、アプリの一部に。
AppleDuo は iPhone Duo を本当に活かしたアプリとゲームを紹介しています。App Store へのリンクを添えて送ってください。ほかの開発者の作品も見られます。