.NET 8 の .NET MAUI(Shell)アプリを iPad(iPadOS 18.2.1)で動かしたときだけ、全ページ上部に「Home」ボタンのような余白や表示が出てしまうことがあります。iPhone / Android では再現しないこの現象を、原因の考え方から iOS 専用カスタマイズでの回避策までまとめます。
現象:iPad(iOS 18 / iPadOS 18)だけ全ページ最上部に「Home」ボタン風の余白が出る
まず症状を整理します。今回のポイントは「iPad だけ」「全ページで同様」「ShellContent の Title に見える文字列が出る(または空のボタンだけ残る)」というところです。
| 項目 | 状況 |
|---|---|
| 発生端末 | iPad(iPadOS 18.2.1) |
| 発生しない端末 | iPhone(同系 iOS 18 でも発生しないことが多い) / Android タブレット |
| 影響範囲 | 特定ページだけでなく、遷移先を含む全ページ上部に常時出る |
| 見た目 | 最上部に余白+「Home」などボタン風の表示(タップできそうな見た目) |
| 関連しそうな設定 | AppShell.xaml の ShellContent Title="Home" に由来しているように見える |
| 試しても改善しない例 | Shell.NavBarIsVisible="False" を AppShell / 各ページ / コードビハインドで設定しても変わらない |
| Title を消した場合 | 文字は消えるが、ボタンっぽい領域(余白)が残ることがある |
「Title を消しても枠だけ残る」という挙動は、単純にラベル文字列が表示されているのではなく、iOS 側で何らかの “コンテナ UI(ボタンの器)” が確保されてしまっている可能性を示唆します。
よくある誤解:NavBar を消したのに、なぜ上部の表示が消えないのか
MAUI の Shell で Shell.NavBarIsVisible="False" を設定すると、多くのケースでは「ナビゲーションバー(タイトルが表示される上部バー)」を非表示にできます。しかし、今回のように iPad(しかも iOS 18)だけで出る「ボタン風の余白」は、NavBar とは別経路で作られている UI であることがあります。
- NavBar は「ページのナビゲーション(戻る、タイトル、ToolbarItems など)」の領域
- 一方、Shell の構成(タブ/フライアウト/タイトル表示)と iPad のサイズクラス(Regular/Compact)によって、iOS 側で別の UI が組み立てられることがある
- その UI が、結果として「ShellContent の Title が載ったボタン風の何か」に見える
つまり「NavBar を消したのに消えない」=設定が間違っている、というよりも、消しているもの(NavBar)と、表示されて困っているもの(iPad iOS 18 の Shell レイアウト由来 UI)が別物という整理が有効です。
原因の考え方:iPad の Regular サイズクラス+iOS 18 の新しい挙動で Shell の見た目が崩れる
iOS では画面の広さや向きによって “サイズクラス(Size Class)” が変わり、同じアプリでも iPhone と iPad で UI の組み立て方が変わります。iPad は基本的に横幅が広く、HorizontalSizeClass が Regular になりやすいのが特徴です。
.NET MAUI の Shell は、このサイズクラスや iPad というデバイス特性に合わせて「タブの出し方」「タイトルの扱い」「フライアウトの見せ方」などを iOS 側で調整します。ところが iOS 18(iPad)では、Shell が想定していないレイアウトパスに入りやすくなり、結果として以下のような現象が起こることがあります。
- タブやタイトル領域の扱いが変化し、上部に “項目を表す UI” が追加されたように見える
- その UI に ShellContent の
Titleが流れ込み、「Home」などがボタン風に表示される Titleを消しても UI の器(領域確保)が残るため、余白や空ボタンに見える
| 観点 | iPhone(多くは Compact) | iPad(多くは Regular) |
|---|---|---|
| HorizontalSizeClass | Compact | Regular |
| Shell の UI ルート | 比較的シンプルな構成になりやすい | よりリッチな構成(広い画面向け)になりやすい |
| 今回の不具合の起点 | その UI ルートに入らず、問題が表面化しにくい | 特定の UI ルートで上部に余計な領域が出やすい |
この種の「OS の新しい挙動 × UI フレームワークの分岐ロジック」で起きる問題は、アプリ側の XAML を少し変えても直らないことが多いです。そこで現実的な回避策として、iPad × iOS 18 のときだけ “サイズクラスを Compact として扱う” というアプローチが効きます。
回避策:iOS の Shell レンダラーをカスタマイズし、iPad(iOS 18 以上)だけ Compact 扱いにする
ここからが本題です。回避の狙いはシンプルで、iPad なのに iPhone 的な UI ルート(Compact 前提)で Shell を描画させることです。これにより、問題の起点となっている iPad Regular 側のレイアウト分岐を避けられます。
実装全体像
| 手順 | やること | 目的 |
|---|---|---|
| MauiProgram.cs | iOS のみ Shell ハンドラー(レンダラー)を差し替える | 標準の Shell 描画をフックして、iOS の挙動を調整する |
| CustomShellRenderer | iPad かつ iOS 18+ のとき HorizontalSizeClass を Compact に上書き | iPad Regular 前提の UI ルートを避け、上部の不要な領域を抑制する |
MauiProgram.cs:iOS のみ Shell を差し替える
MauiProgram.cs の CreateMauiApp 内で、iOS のときだけ Shell を差し替えます。ポイントは「他プラットフォームに影響を出さない」ことです。
.ConfigureMauiHandlers(handlers =>
{
#if IOS
handlers.AddHandler(typeof(Shell), typeof(CustomShellRenderer));
#endif
});
この設定によって、iOS 実行時に Shell の描画が CustomShellRenderer に切り替わります。
CustomShellRenderer:iPad × iOS 18+ だけ Compact を強制する
iOS プロジェクト側(例:Platforms/iOS 配下など)に CustomShellRenderer.cs を作成し、ShellItemRenderer に trait override を設定します。
#if IOS
using UIKit;
// ShellRenderer / ShellItemRenderer の名前空間はプロジェクト構成により異なるため、
// 既存の ShellRenderer を参照できる using を追加してください。
public class CustomShellRenderer : ShellRenderer
{
protected override IShellItemRenderer CreateShellItemRenderer(ShellItem item)
{
var renderer = base.CreateShellItemRenderer(item);
if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad
&& UIDevice.CurrentDevice.CheckSystemVersion(18, 0)
&& renderer is ShellItemRenderer shellItemRenderer)
{
// iPad でも Compact 扱いにすることで、iOS 18 iPad 固有の表示崩れを回避
shellItemRenderer.TraitOverrides.HorizontalSizeClass = UIUserInterfaceSizeClass.Compact;
}
return renderer;
}
}
#endif
この実装で狙っているのは「iPad でありながら、横幅のサイズクラスを Compact として Shell の描画パスを変える」ことです。結果として、全ページ上部に現れていた “Home ボタン風の余白” が抑制されるケースがあります。
実装のコツ:適用範囲を “必要最小限” にする
回避策は強力ですが、iPad でサイズクラスを変えると UI 全体の挙動も変わり得ます。そこで、条件をしっかり絞るのが重要です。
- iPad のみに限定:
UserInterfaceIdiom == Pad - iOS 18 以上のみに限定:
CheckSystemVersion(18, 0) - Shell の該当レンダラーに限定:
renderer is ShellItemRenderer
また、将来 iOS 19 以降で状況が変わった場合に備え、「18.x のみに適用する」などの範囲指定を行うこともできます。
if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad
&& UIDevice.CurrentDevice.CheckSystemVersion(18, 0)
&& !UIDevice.CurrentDevice.CheckSystemVersion(19, 0)
&& renderer is ShellItemRenderer shellItemRenderer)
{
shellItemRenderer.TraitOverrides.HorizontalSizeClass = UIUserInterfaceSizeClass.Compact;
}
「OS 側・フレームワーク側で根本修正が入ったら回避策を外したい」という運用を考えるなら、こうした条件分岐は特におすすめです。
確認ポイント:本当に “ShellContent Title が原因に見える表示” なのかを切り分ける
見た目が「Home」だったとしても、アプリ内のどの Title が出ているかで対応方針が変わることがあります。Shell では似たプロパティが多いため、切り分けの観点を表にしておきます。
| 表示に関係しやすい要素 | 設定場所 | 用途 | 今回の症状との関係 |
|---|---|---|---|
| ShellContent Title | AppShell.xaml | タブ項目名/ナビゲーション項目名に使われる | 「Home」と一致しているなら強く疑う |
| FlyoutItem Title | AppShell.xaml | フライアウトの項目名 | フライアウト構成次第で上部に影響することがある |
| Page.Title | 各ページ | ナビゲーションバー上のタイトル | NavBar を消すと通常は見えなくなる |
| Shell.TitleView | AppShell.xaml | ナビゲーションバーに任意 UI を埋め込む | iOS 18 iPad で期待通りにならないケースが出やすい |
「Title を消すと文字だけ消えるが器が残る」という場合は、“Title が器を作っている” のではなく “器は別にあり、Title がその中の表示要素に流れ込んでいる”と考えると説明がつきます。今回のような trait override による回避は、この “器” を作っているレイアウト分岐自体を避けるための手段です。
再現手順を最小化して検証する
チーム開発や不具合切り分けでは「再現できる最小構成」を用意すると、原因がアプリ固有なのかフレームワーク/OS なのか判断しやすくなります。以下は検証の進め方の一例です。
| ステップ | やること | 期待する観察 |
|---|---|---|
| 1 | .NET MAUI の Shell テンプレートを新規作成 | ベースライン(素の状態)を確認できる |
| 2 | AppShell.xaml で ShellContent に Title を明示(例:Home) | 問題の表示が Title と紐づいているか確認できる |
| 3 | iPadOS 18.2.1 実機(または該当シミュレータ)で実行 | iPad だけで上部に余白/ボタン風が出るか |
| 4 | NavBarIsVisible を False にして変化を見る | NavBar ではないことを確認できる |
| 5 | CustomShellRenderer の trait override を適用して再実行 | 症状が消える/軽減するかを確認できる |
この手順で「最小構成でも再現する」なら、アプリ固有のレイアウトではなく、iOS 18(iPad)× MAUI Shell の組み合わせで起きている可能性が高くなります。
副作用と注意点:iPad を Compact 扱いにするトレードオフ
iPad を Compact 扱いにすると、意図しない UI 変化が起きる可能性があります。実際の影響はアプリの Shell 構成(Tabs / Flyout / 複数階層ナビゲーション)によって変わります。
| 起こり得る影響 | 具体例 | 対処・考え方 |
|---|---|---|
| フライアウト表示方式の変化 | iPad で常時表示されていたサイドメニューが、オーバーレイ表示に変わる | 「iPad は常時サイドバーが欲しい」要件がある場合は要注意 |
| タブの表示位置/見え方の変化 | タブが iPhone ライクな見た目に寄る | 今回の不具合回避が優先なら許容、UI 要件が厳しいなら別案検討 |
| レイアウト全体のブレ | 横画面時に想定していた余白や表示密度が変わる | 影響が大きい場合は「該当画面だけ別ナビゲーション」に切り分ける |
とはいえ今回の回避策は「iOS 18 iPad だけ」「必要なときだけ」に限定できるため、不具合による UX 破綻を止血する用途としては非常に実用的です。まずは影響範囲を確認し、問題が出る画面・端末・OS バージョンでのみ適用するのが現実解になりやすいです。
実装を安定させるためのチェックリスト
実装後に「直ったように見えるが別の画面で変」「デバッグビルドだけ挙動が違う」といった状況を避けるため、確認観点をチェックリスト化しておきます。
| チェック項目 | 確認方法 | 理由 |
|---|---|---|
| iPad(iOS 18)で上部の余白/ボタン風 UI が消える | 問題が出ていた画面を複数遷移して確認 | 「初期ページだけ」「特定ルートだけ」などを見落とさないため |
| iPhone の見た目が変わっていない | 同一ビルドで iPhone 実機/シミュレータ確認 | 条件分岐が漏れると全 iOS に影響するため |
| Android / Windows など他プラットフォームに影響しない | #if IOS の範囲を確認 | ハンドラー差し替えが iOS 以外に波及しないため |
| 横画面/縦画面での差分 | 回転や Split View(可能なら)で確認 | サイズクラス関連は回転・分割で変化しやすい |
| ToolbarItems / TitleView を使っている画面 | ツールバーを持つ画面で表示確認 | 上部 UI の分岐に関係しやすい |
補足:この手の不具合は “アプリのミス” ではなく、OS / フレームワークの境界で起きやすい
iOS のメジャーバージョン更新(今回なら iOS 18 / iPadOS 18)は、サイズクラスやナビゲーション UI の内部実装が微妙に変わることがあります。MAUI の Shell は OS ネイティブのコンテナ(ナビゲーション、タブ、フライアウト等)を組み合わせて表示するため、OS 側の変更の影響を受けやすい領域です。
同様の症状や Shell のタイトル表示周り(TitleView を含む)については、コミュニティでも報告が出ることがあります。根本修正はフレームワーク側の更新で入ることが多いため、将来的には MAUI のアップデートで解消する可能性もあります。一方で、プロダクションアプリでは「修正を待つ」より先にユーザー影響を止めたい場面が多く、今回のような “限定的な trait override” は実務で効きやすい回避策です。
まとめ:iPad(iOS 18)限定の “Home ボタン風の余白” は ShellRenderer の trait override で止血できる
- iPadOS 18 の iPad だけ、全ページ上部に「Home」ボタン風の余白が出る場合がある
Shell.NavBarIsVisible="False"で消えないなら、NavBar 以外の UI が作られている可能性が高い- 回避策として、iOS の ShellRenderer をカスタマイズし、iPad(iOS 18+)だけ HorizontalSizeClass を Compact に上書きする
- 副作用(iPad の UI が iPhone 寄りになる)もあり得るため、OS バージョンや端末を絞って最小限に適用する
上部の余白がユーザー体験を大きく損ねるタイプの不具合は、放置すると離脱にも直結します。まずは限定的な回避策で安定稼働を優先しつつ、将来の MAUI 更新で根本解決できるタイミングが来たら条件分岐を外す、という運用が現実的です。

コメント