日程Fit|「いつ空いてますか?」の往復はもう不要。候補日を選んでURLを送るだけ|登録不要|今すぐ無料で使う →

.NET MAUI Shellのフライアウト区切り線を消す方法|FlyoutItemとShellContentのセパレーター対策

.NET MAUI の Shell でフライアウト(ハンバーガーメニュー)を組むと、FlyoutItem と ShellContent の境目に灰色の区切り線が突然入り、意図しない「別グループ」表示になることがあります。見た目の違和感だけでなく、ShellContent にページが無いと例外の原因にもなるため、仕組みを整理しつつ、要件を崩さずに解消する実装パターンをまとめます。

日程Fit。無料・登録不要。「いつ空いてる?」を、ひとつのリンクで。リンクを送って、○△×でかんたん日程調整。無料で日程を作る。
目次

.NET MAUI Shell のフライアウトで起きる「灰色の区切り線」問題とは

Shell を採用すると、フライアウトにページ(ナビゲーション先)を並べるだけでなく、タブ構成や階層をまとめて宣言できます。一方で、構成の組み合わせによっては、フライアウト内でメニューが自動的に「グルーピング」され、その境界として灰色の区切り線(セパレーター)が描画されます。

今回の典型例は次のようなケースです。

  • 主要画面は FlyoutItem にまとめ、FlyoutDisplayOptions="AsMultipleItems" で子要素を複数行として表示している
  • 「Sign Out(ログアウト)」を ShellContent として Shell 直下に追加している(または FlyoutItem と並列に配置している)

このとき、FlyoutItem の並び単独の ShellContent が「別セクション」として扱われやすく、結果として境界線が出ます。さらに、Sign Out がページを持たない ShellContent だと、タップ時にナビゲーションできず例外になる可能性があります。

再現しやすい XAML 構成(よくある書き方)

見た目の問題が出やすい構造を、最小化したイメージで示します(実際のページ名やルートはプロジェクトに合わせてください)。

<Shell
    x:Class="MyApp.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MyApp">









 

上記だと、フライアウトに「Home(子項目が複数)」と「Sign Out(単独)」が並び、間に区切り線が入ることがあります。さらに ShellContent Title="Sign Out"ContentTemplate を持たないため、タップ時に No Content found for ShellContent... のような例外へつながるリスクがあります。

なぜ区切り線が出るのか:Shell の「表示単位」と「役割」を整理する

この問題を最短で理解するコツは、Shell がフライアウトを次のように扱う点です。

  • FlyoutItem / TabBar / MenuItem / ShellContent など、要素の種類ごとに「表示のまとまり」を作る
  • FlyoutDisplayOptions により、子要素(ShellContent)を まとめて 1 行 にするか、複数行に展開 するかが変わる
  • 役割が異なる要素(ページ遷移 vs 操作)を同列に置くと、UI 上「別グループ」に見せるための区切りが入りやすい
宣言要素フライアウトでの見え方向いている用途注意点
FlyoutItem「親」として扱われ、表示オプション次第で子項目を展開主要画面群(Home / Settings など)AsMultipleItems だと子項目が“独立行”として並ぶ
ShellContent基本は「ページへの入口」実体ページを持つ画面ContentTemplate/ContentPage が無いとナビゲーションできず例外になり得る
MenuItem「操作メニュー」として別枠(多くの場合下部)に出るログアウト、キャッシュ削除などUI 的に区切りが入るのはむしろ自然(別枠であることを示す)
FlyoutHeader / FlyoutFooterフライアウトの上部/下部に自由な UI を配置できるユーザー情報、ログアウトボタン、バージョン表示完全に自前 UI なので見た目・挙動をコントロールしやすい

今回の「灰色の区切り線」は、バグというより “別のまとまり”として描画するためのデフォルト表現 に近い挙動です。つまり、解消の方向性は次の 2 つに整理できます。

  • UI のまとまりを変える(= AsSingleItem にしてグルーピングを変える)
  • そもそもログアウトを ShellContent(ページ)として扱わず、操作として配置する

解決策:FlyoutDisplayOptions を AsSingleItem にする(最短で消す)

まず一番手軽なのは、FlyoutItem 側の表示を AsSingleItem に変える方法です。

&lt;FlyoutItem Title="Home" FlyoutDisplayOptions="AsSingleItem"&gt;
  &lt;ShellContent Title="Dashboard"
                ContentTemplate="{DataTemplate local:DashboardPage}" /&gt;
  &lt;ShellContent Title="Settings"
                ContentTemplate="{DataTemplate local:SettingsPage}" /&gt;
&lt;/FlyoutItem&gt;

AsSingleItem にすると、FlyoutItem が「1 行の親」として表示され、子の ShellContent は展開(タップでサブ項目として見せる、またはタブとして扱う等)になりやすく、結果として区切り線が目立たなくなったり、出なくなったりします。

観点AsSingleItemAsMultipleItems
フライアウトの見え方親(Home)中心でシンプル子項目(Dashboard/Settings)が並び分かりやすい
区切り線の出やすさ低い(まとまりが 1 行に寄る)高い(まとまりが増える)
要件との相性「Home だけ出ればよい」なら適合「複数項目を常に見せたい」なら適合

ただし、要件として フライアウトに複数項目を常に並べたい(= AsMultipleItems が必須)場合、この方法は合いません。そこで次の推奨策に進みます。

解決策:AsMultipleItems のままなら「Sign Out を ShellContent にしない」(推奨)

ログアウトは多くのアプリで「ページ」ではなく「操作」です。つまり、ShellContent(ページの入口)に押し込むほど不自然になり、UI の区切り線・例外・メンテナンス性の面で不利になります。

ここからは、AsMultipleItems を維持しつつ、ログアウトを安全に実装する代表的な 3 パターンを紹介します。

パターンA:FlyoutFooter にログアウトボタンを置く(見た目を崩しにくい)

フライアウトの末尾にボタンを固定表示できるため、メニュー項目と「操作」を視覚的に分けられます。区切り線を出したくない場合も、フッター側のレイアウトを自分で作れるのが強みです。

&lt;Shell
    x:Class="MyApp.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"&gt;

  &lt;FlyoutItem Title="Home" FlyoutDisplayOptions="AsMultipleItems"&gt;
    &lt;ShellContent Title="Dashboard"
                  ContentTemplate="{DataTemplate local:DashboardPage}" /&gt;
    &lt;ShellContent Title="Settings"
                  ContentTemplate="{DataTemplate local:SettingsPage}" /&gt;
  &lt;/FlyoutItem&gt;

  &lt;Shell.FlyoutFooter&gt;
    &lt;Grid Padding="16"&gt;
      &lt;Button Text="Sign Out"
              Clicked="OnSignOutClicked" /&gt;
    &lt;/Grid&gt;
  &lt;/Shell.FlyoutFooter&gt;

&lt;/Shell&gt;

コードビハインドで処理する場合は次のイメージです(MVVM で Command 化する場合は次パターンBも参照してください)。

private async void OnSignOutClicked(object sender, EventArgs e)
{
    // フライアウトを閉じる(操作感が良くなる)
    Shell.Current.FlyoutIsPresented = false;


// 例:確認ダイアログ
bool ok = await DisplayAlert("Sign Out", "ログアウトしますか?", "はい", "いいえ");
if (!ok) return;

// 例:トークン破棄や状態初期化(実装はアプリ設計に合わせる)
// await SecureStorage.Default.SetAsync("access_token", string.Empty);
// Preferences.Default.Clear();

// 例:ログイン画面へ戻す(ルート設計に合わせて)
await Shell.Current.GoToAsync("//Login");


} 

ポイントは、ログアウトが「ページ」ではなく「処理+遷移」なので、Shell のナビゲーション構造から切り離す方がトラブルが減ることです。

パターンB:MenuItem を使って “操作” として宣言する(MVVM と相性が良い)

Shell には「ページ」以外のメニューとして MenuItem があります。Command をバインドできるため、MVVM を徹底しているプロジェクトでは扱いやすい選択肢です。

<Shell
    x:Class="MyApp.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">








 

MenuItem は多くの場合、通常のページリストとは別枠として表示されます。区切り線が入ることはありますが、それは「操作は別枠」という UX になっているため、むしろ自然です。どうしても線が不要なら、パターンAの FlyoutFooter の方がコントロールしやすいです。

パターンC:FlyoutHeader にボタンを置く(ユーザー情報と一体化したい場合)

ユーザー名やアイコンをヘッダーに表示しているアプリでは、ログアウトをヘッダーに置くと導線が分かりやすくなります。質問の例のように、ヘッダー UI の下にボタンを足すだけで実現できます。

&lt;Shell.FlyoutHeader&gt;
  &lt;StackLayout Padding="16" Spacing="12"&gt;
    &lt;!-- 例:ユーザー情報エリア --&gt;
    &lt;Grid ColumnDefinitions="Auto,*" ColumnSpacing="12"&gt;
      &lt;Image Source="user.png" HeightRequest="40" WidthRequest="40" /&gt;
      &lt;StackLayout Grid.Column="1" Spacing="2"&gt;
        &lt;Label Text="{Binding UserName}" FontAttributes="Bold" /&gt;
        &lt;Label Text="{Binding UserEmail}" FontSize="12" /&gt;
      &lt;/StackLayout&gt;
    &lt;/Grid&gt;

    &lt;!-- ログアウトボタン --&gt;
    &lt;Button Text="Sign Out" Clicked="OnSignOutClicked" /&gt;
  &lt;/StackLayout&gt;
&lt;/Shell.FlyoutHeader&gt;

ヘッダー配置は「ページ一覧」と分離されるため、FlyoutItem と ShellContent の間に出ていた区切り線問題を根本から回避しやすい構成です。

ログアウトを安定させる実務的なチェックリスト

UI だけ直しても、ログアウトの実装が曖昧だと「ログアウトしたはずなのに戻るボタンで復帰できた」「一部キャッシュが残った」などの事故が起きます。メニュー構造を直すタイミングで、処理も一緒に整えるのがおすすめです。

項目狙い実装ヒント
フライアウトを閉じるタップ後の操作感を良くするShell.Current.FlyoutIsPresented = false;
二重タップ対策多重実行で状態が壊れるのを防ぐボタンを一時的に無効化、またはコマンドの CanExecute 制御
認証情報の破棄再利用を防ぐSecureStorage/Preferences の削除、メモリ上のトークン破棄
画面スタックのリセット戻るで復帰できないようにするGoToAsync("//Login") のような絶対ルート遷移を検討
必要ならサーバー側の無効化盗難トークンを無効化リフレッシュトークン失効 API を呼ぶ、デバイス登録解除など

特に Shell を使うアプリでは、ログアウト後に “戻る” で以前のページに戻れてしまうケースが起きがちです。ログアウト後の画面遷移は、スタックが残らない形(絶対ルート遷移や、認証状態に応じた初期ルート切り替え)を意識すると安全です。

どうしても「Sign Out 画面」を作りたい場合の正しい ShellContent

アプリの要件として「ログアウト前に注意事項を表示したい」「アカウント切り替え UI を出したい」など、ログアウト専用ページが必要なこともあります。その場合は ShellContent として置いても構いませんが、必ず ContentPage(ContentTemplate)を持たせるのが前提です。

&lt;ShellContent Title="Sign Out"
              Route="signout"
              ContentTemplate="{DataTemplate local:SignOutPage}" /&gt;

SignOutPage 側では、ボタン押下でログアウト処理を実行し、完了後にログイン画面へ遷移させます。ShellContent を “操作” として使うのではなく、“ページ” として完結させると、責務が明確になります。

区切り線が消えない・挙動が揃わないときの追加チェック

同じ XAML でも、スタイルやテンプレート、プラットフォーム差で見え方が変わることがあります。最後に、実務でハマりやすい確認ポイントをまとめます。

  • ShellContent が混在していないか:Shell 直下に複数の ShellContent を置くと、セクションが増え区切りが入りやすくなります。意図が「ページ一覧」なのか「操作」なのかで置き場所を分けます。
  • FlyoutItem のまとまりを見直す:Home/Settings などの“主要導線”は FlyoutItem に寄せ、例外的な項目だけが外に出ないようにします。
  • 例外が出ていないか:タップ時の例外が出ている場合、見た目の問題より先に ContentTemplate の未設定を疑います。
  • ヘッダー/フッターの余白:FlyoutHeader/FlyoutFooter のレイアウトが大きすぎると、メニューがスクロールしづらくなります。Padding と最小限の UI を意識します。

まとめ:区切り線の正体は「グルーピング」、ログアウトは “操作” として扱う

FlyoutItem と ShellContent の間に出る灰色の区切り線は、Shell がメニューを「まとまり」で描画している結果です。最短で消したいなら FlyoutDisplayOptions="AsSingleItem" が効きますが、AsMultipleItems を維持したいなら、ログアウトを ShellContent で表現しないのが安全です。

おすすめは FlyoutFooter / FlyoutHeader にボタンを置く、または MenuItem を使って Command として宣言すること。ページ遷移の責務と、操作の責務を分けるだけで、見た目・例外・保守性をまとめて改善できます。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次