.NET MAUIで画面を組むと、縦横に並べるだけならVerticalStackLayout/HorizontalStackLayoutが快適です。ところが少し複雑になると「FillAndExpandが欲しい…」となり、StackLayoutに戻りたくなることも。ここではAndExpandの正体を整理し、Grid(*)で安全に置き換える実務パターンをまとめます。
結論:単純な縦/横並びはStack系、領域配分(伸びる)はGridが最適解
最初に結論を固定します。迷ったらこのルールに戻ると、画面設計がブレにくくなります。
| やりたいこと | 推奨レイアウト | 理由(実務目線) |
|---|---|---|
| 単純な縦積み(フォーム、設定画面、説明文+ボタンなど) | VerticalStackLayout | 意図が明確で読みやすい。StackLayoutより最適化されている前提で使える。 |
| 単純な横並び(アイコン+テキスト、左右ボタンなど) | HorizontalStackLayout | 同上。Orientationの指定が不要で、構造が単純。 |
| 「余った領域を誰が取るか」を明確にしたい(スクロール領域、一覧、空白スペーサーなど) | Grid(* / Auto) | AndExpandでやりたかった領域配分を、行/列で明示できる。保守が楽。 |
| 折り返し・可変配置(タグのように並べる、レスポンシブ風に回り込み) | FlexLayout | StackやGridで無理にやるより素直。だが乱用すると意図が読みにくいので限定的に。 |
つまり、「StackLayoutを使い続けていいのか」問題は、AndExpandに依存しない設計へ寄せると自然に解消します。AndExpandが必要になった瞬間に「Gridの出番」と判断するのが一番安全です。
AndExpand(FillAndExpandなど)の正体:子ではなく“親(StackLayout)”の都合で効く仕組み
まず誤解されやすい点を整理します。FillAndExpand / CenterAndExpand などは、見た目としては「要素が伸びる魔法」ですが、実態はLayoutOptionsの“Expandフラグ”で、これを解釈するかどうかは親レイアウト次第です。
AndExpandが意味を持つのは、基本的にStackLayoutだけ
AndExpandは、Xamarin.Forms時代からの互換的な挙動として、主にStackLayoutが「余った領域をExpand指定の子に配る」ために存在します。逆に言うと、StackLayout以外(GridやFlexLayoutなど)では、Expandの解釈がされず“効いたように見えない/実は無意味”になりがちです。
ここで重要なのは、AndExpandは「子が勝手に伸びる」のではなく、親が子に領域を配分するための目印だという点です。親がその目印を見ないなら、何も起きません。
積み方向と直交するAndExpandは、StackLayout内でも無意味になりやすい
StackLayoutは「積み方向(縦 or 横)」に沿って子要素を並べます。AndExpandで“余りを配る”のも基本は積み方向です。
| 親がStackLayoutで… | 意味が出やすい指定 | 整理対象になりやすい指定 | コメント |
|---|---|---|---|
| 縦積み(Vertical) | 子のVerticalOptions=”FillAndExpand” など | 子のHorizontalOptions=”CenterAndExpand” など | 横方向はFill/Center/Endなどの“配置”は効くが、Expandは余り配分の対象外になりやすい。 |
| 横積み(Horizontal) | 子のHorizontalOptions=”FillAndExpand” など | 子のVerticalOptions=”CenterAndExpand” など | 縦方向のExpandは読み手に誤解を与えやすい(「伸びるはず」と期待する)ので削除候補。 |
実務的には、「AndExpandを付けたのに効いてない」のほとんどがこのパターンです。レイアウトの読みやすさも落ちるので、まずはここを掃除すると画面の挙動が安定します。
なぜVerticalStackLayout/HorizontalStackLayoutを使うのか
.NET MAUIでは、StackLayoutの代わりにVerticalStackLayout / HorizontalStackLayoutが用意されています。目的はシンプルで、よく使う縦積み・横積みのケースを分けることで、意図が明確になり、内部的にも最適化しやすくなるからです。
ただし、ここが今回のテーマの核心ですが、AndExpandに依存した「余りを配る」設計を続けると、どうしてもStackLayoutに戻りたくなります。そこで、次の章でAndExpandをGridに翻訳する考え方を固定します。
AndExpandをGrid(*)へ置き換える発想:Autoと*で「伸びる領域」を宣言する
AndExpandがやりたかったことは、乱暴に言えば「余った領域を取る(伸びる)」です。これをGridでは、行(RowDefinitions)や列(ColumnDefinitions)にスターサイズ(*)を使うことで、はるかに明示的に表現できます。
GridのAuto / * を実務でどう使い分けるか
| 指定 | 意味 | 向いている要素 | よくある例 |
|---|---|---|---|
| Auto | 内容に必要な分だけ確保 | ヘッダー、ラベル、固定ボタン列 | タイトル、検索バー、フッターボタン |
| *(スター) | 余った領域を取る(伸びる) | スクロール領域、一覧、可変の本文 | CollectionView、ScrollView、エディタ領域 |
| 2* / 3* | 比率で配分 | 左右ペイン、上段/下段の比率 | 左メニュー:右コンテンツ=1*:3* |
AndExpandは「Expand指定の子が複数あると均等配分」になりやすく、微調整が面倒になりがちです。Gridなら2*や3*で比率を指定できるので、画面の要件が増えても破綻しにくいのが大きな利点です。
置き換えレシピ:FillAndExpandが出てきたらGridに翻訳する
ここからは「実務でそのまま貼って使える」置き換えパターンです。AndExpandを見かけたら、まずは次のテンプレートを当てはめてください。
パターン:ヘッダー固定+本文が伸びる+フッター固定
最も出現率が高い構成です。StackLayout+ScrollView(または一覧)がFillAndExpandになっている場合は、ほぼこの置き換えで解決します。
Before(StackLayout+FillAndExpand)
<StackLayout Padding="16">
<Label Text="設定" FontSize="24" />
After(Grid+Auto,*,Auto)
<Grid Padding="16"
RowDefinitions="Auto,*,Auto">
この形にしておくと、後から「フッターを2段にする」「ヘッダーに検索欄を足す」「本文をCollectionViewにする」などの変更が入っても、行定義を触るだけで対応できます。
パターン:左右(または上下)で片方だけ伸びる
横方向のFillAndExpandを使って「右側だけ伸びる入力欄」を作っている場合は、GridのAuto,*が定番です。
Before(Horizontal StackLayout+FillAndExpand)
<StackLayout Orientation="Horizontal" Spacing="12">
<Label Text="名前" VerticalOptions="Center" />
<Entry HorizontalOptions="FillAndExpand" />
</StackLayout>
After(Grid+Auto,*)
<Grid ColumnDefinitions="Auto,*" ColumnSpacing="12">
<Label Text="名前" VerticalOptions="Center" />
<Entry Grid.Column="1" />
</Grid>
この置き換えは見た目の再現度が高く、かつコードレビューで「右が伸びる構造」が一目で分かります。
パターン:間に“余白スペーサー”を入れて下に押し下げたい
「上に説明、下にボタン。間は空けたい」系の画面では、AndExpandを“スペーサー用のBoxView”に付けていることがあります。Gridならもっと自然に書けます。
Before(スペーサーがFillAndExpand)
<StackLayout Padding="16">
<Label Text="説明文" />
After(Gridの*行がスペーサーになる)
<Grid Padding="16" RowDefinitions="Auto,*,Auto">
<Label Text="説明文" />
“何も置かない行”を作れるのがGridの強みです。ダミー要素が消えるので、アクセシビリティやテスト面でも有利です。
「AndExpandが効かない」典型パターンと、削除してよいサイン
既存コードの整理をするときに、まず当たりを付けやすいポイントをまとめます。AndExpandを闇雲に消すのではなく、“親が何か”と“積み方向が何か”だけ確認すれば、削除可否の判断はかなり簡単になります。
親がGrid/FlexLayout/AbsoluteLayout/ScrollViewなのにAndExpandが付いている
この場合、AndExpandは効いていないか、意図通りではないことがほとんどです。
- まずはExpandを外して見た目が変わるかを確認(変わらないなら削除してOK)。
- 「伸ばしたい」意図があるなら、親をGridにして*行/*列で表現する。
縦積みなのにHorizontalOptions=”…AndExpand” が混ざっている
縦に積むStackLayout(またはVerticalStackLayout)で、横方向のAndExpandが混ざっているのは、保守上かなり危険です。次のように置き換えると意図が明確になります。
Before(誤解されやすい)
<StackLayout>
<Label Text="タイトル"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
After(意図通りならこれで十分)
<VerticalStackLayout>
<Label Text="タイトル"
HorizontalOptions="Center" />
</VerticalStackLayout>
“Centerなのか、Fillなのか、余白も含めて伸ばしたいのか”を混ぜないことが、レイアウト事故を防ぐコツです。
Gridで置き換えるときにハマりやすい注意点
AndExpand → Grid(*)の置き換えは強力ですが、いくつか落とし穴もあります。ここを押さえると、移行が一気に楽になります。
ScrollViewの“中”では*(スター)が期待通りに動かないことがある
ScrollViewは「中身をスクロールできるように」高さ(または幅)の制約が緩くなりやすいレイアウトです。結果として、ScrollViewの中にGridを置いたときに*行が“余り”を認識できず、伸びないことがあります。
- 「画面全体で伸びる領域」を作りたい場合は、Gridの*行にScrollViewを置く(ScrollViewを外側へ)
- 「ScrollViewの中で比率を取りたい」は、発想を変えてAuto中心にするか、UI要件自体を見直す(スクロール領域内での“余り”は定義しにくい)
この違いを理解しておくと、「Gridにしたのに伸びない」問題を早い段階で切り分けできます。
Gridを“全部”に使うのではなく、骨格だけGridにする
Gridは万能ですが、細部までGridで組むと、行/列が増えて逆に読みづらくなります。おすすめは「画面の骨格だけGrid」+「セル内はVerticalStackLayout/HorizontalStackLayout」です。
例:骨格をGrid、内容はStack系で読みやすく
<Grid RowDefinitions="Auto,*,Auto" Padding="16">
<Grid ColumnDefinitions="Auto,*" ColumnSpacing="12">
<Label Text="メモ" VerticalOptions="Start" />
<Editor Grid.Column="1" AutoSize="TextChanges" />
</Grid>
</VerticalStackLayout>
こうすると、構造はGridで“領域配分”を担保しつつ、内容はStack系でスッキリ書けます。
「StackLayoutは将来なくなる?」不安への現実的な向き合い方
「StackLayoutが廃止されたら困るから、今のうちに全部置き換えた方がいいのか?」という不安は自然です。ただ実務の判断は、白黒ではなく“影響範囲を小さくする”方向が現実的です。
- 新規実装は、基本をVerticalStackLayout/HorizontalStackLayout+Gridに寄せる
- 既存画面は、AndExpandが絡む箇所から優先してGridへ(挙動のバグ混入を減らしやすい)
- 移行の目的は「廃止対策」よりも、レイアウトの意図を明文化して保守性を上げることに置く
StackLayout自体は互換性の観点から残り続ける可能性もありますが、将来どうなるかを100%予測するより、AndExpandへの依存を減らしておく方が、結果的に移行コストも障害も減ります。
移行の進め方:AndExpand駆動から“宣言的な領域配分”へ
大きな画面を一気に書き換えると事故りやすいので、順番を決めて進めると安全です。
手順のおすすめ
- Step 1:画面の最外枠をGridにする(Auto,*,Autoなど)
- Step 2:FillAndExpandが付いていた要素を、*行/*列へ移す
- Step 3:StackLayoutをVerticalStackLayout/HorizontalStackLayoutへ置換(AndExpandが残っていない箇所から)
- Step 4:“効いていないAndExpand”を削除し、見た目が変わらないことを確認
- Step 5:余白(Margin/Spacing)と整列(HorizontalOptions/VerticalOptions)を最終調整
検証を楽にするコツ
- 一時的に各ブロックへ背景色(またはBorder)を付けて、領域の境界を可視化する
- 端末サイズを変えて(スマホ縦/横、タブレット)レイアウトが破綻しないか確認する
- 一覧が絡む場合は、ScrollViewではなくCollectionViewの利用も検討する(大量要素での体感が変わる)
よくある質問(現場で詰まりやすいポイント)
FillとFillAndExpandの違いは何ですか?
Fillは「与えられた領域の中で、要素を伸ばして埋める(ストレッチする)」ニュアンスです。一方でExpandは「余った領域を自分に割り当ててもらう」ニュアンスで、親(主にStackLayout)の配分ロジックに依存します。混ぜると理解が難しくなるので、領域配分はGrid、要素の伸縮はFill、という風に役割を分けると整理しやすいです。
Gridにしたら、以前よりコードが増えませんか?
最初はRowDefinitions/ColumnDefinitionsが増えるため増えたように見えます。ただ、画面要件が増えたときにAndExpandの追加や順番調整で泥沼化するリスクが減るため、トータルでは保守が楽になるケースが多いです。特に「固定ヘッダー/固定フッター/中央が伸びる」構造は、Gridで型を作ってしまうと圧倒的に安定します。
VerticalStackLayoutだけでどうにかなりませんか?
単純なフォームなら十分いけます。ただ「中央だけ伸びる」「左右比率で配分する」「下に固定ボタンを置く」などが出た時点で、Stack系だけで頑張るとAndExpand依存やダミー要素が増えやすくなります。そこがGridへ切り替える合図です。
まとめ:迷いを消すためのチェックリスト
- 単純な縦/横並びはVerticalStackLayout/HorizontalStackLayout
- 「余った領域を取る」が必要ならGridの*(スターサイズ)
- AndExpandは親がStackLayout以外なら基本的に期待しない
- StackLayout内でも、積み方向と直交するAndExpandは整理対象
- 画面の骨格をGridにして、セル内はStack系にすると読みやすさと拡張性が両立
AndExpandは便利に見えますが、設計の主導権が“子”ではなく“親の配分ロジック”に寄るため、画面が育つほどコントロールしづらくなります。Grid(Autoと*)で領域配分を宣言し、Stack系は「並べる」役に徹させる。これが.NET MAUIでレイアウトを安定させる一番実務的な落とし所です。

コメント