Xamarin.Formsで思い通りのレイアウトを組みたい。 そんな時には、レイアウト系のコントロールを押さえておくといいです。
公式ドキュメント
Layoutコントロール
Xamarin.Formsでは、複数のコントロールを配置するときには、あらかじめ定義されている子要素をレイアウトする機能をもったコントロールに対して、コントロールを配置、もしくはレイアウトコントロールをネストさせて配置します。以下のコントロールが提供されています。
- StackLayout
- AbsoluteLayout
- RelativeLayout
- Grid
- ScrillViewer
ここでは、おさえておくべき必要最低限のレイアウトコントロールとしてStackLayout
とGrid
について紹介したいと思います。
StackLayout
StackLayout
は、名前の通り子要素を縦方向、横方向に並べて配置するコントロールになります。デフォルトでは縦方向に子要素を並べて配置します。デフォルトの挙動を確認するためのXAMLを以下に示します。
<?xml version="1.0" encoding="utf-8"?><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"prism:ViewModelLocator.AutowireViewModel="True"x:Class="PrismUnityApp15.Views.MainPage"Title="MainPage"><StackLayout><BoxView Color="Red" /><BoxView Color="Blue" /><BoxView Color="Green" /><BoxView Color="Aqua" /></StackLayout></ContentPage>
実行すると以下のような表示になります。
縦と横の表示を切り替えるにはOrientation
プロパティを指定します。Vertical
がデフォルトでHorizontal
を指定することで、横方向に並ぶようになります。XAMLを以下に示します。
<?xml version="1.0" encoding="utf-8"?><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"prism:ViewModelLocator.AutowireViewModel="True"x:Class="PrismUnityApp15.Views.MainPage"Title="MainPage"><StackLayout Orientation="Horizontal"><BoxView Color="Red" /><BoxView Color="Blue" /><BoxView Color="Green" /><BoxView Color="Aqua" /></StackLayout></ContentPage>
実行すると以下のような表示になります。
Spacing
Spacing
プロパティを使うことでコントロールを並べるときの余白を指定することもできます。
<?xml version="1.0" encoding="utf-8"?><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"prism:ViewModelLocator.AutowireViewModel="True"x:Class="PrismUnityApp15.Views.MainPage"Title="MainPage"><StackLayout Orientation="Horizontal"Spacing="20"><BoxView Color="Red" /><BoxView Color="Blue" /><BoxView Color="Green" /><BoxView Color="Aqua" /></StackLayout></ContentPage>
実行すると以下のようになります。
コントロール間のスペースが広くなっていることが確認できます。
LayoutOptions
さらにコントロールのHorizontalOptions
プロパティとVerticalOptions
を使うことで子コントロールがStackLayout
上で占める割合をある程度自由に設定することができます。
HorizontalOptions
プロパティとVerticalOptions
プロパティには以下の値が設定できます。
- Start: 開始位置にレイアウトする
- Center: 中央にレイアウトする
- End: 終端にレイアウトする
- Fill: いっぱいに広げる
- StartAndExpand: 開始位置にレイアウトして余白を埋めつくす
- CenterAndExpand: 中央にレイアウトして余白を埋め尽くす
- EndAndExpand: 終了位置にレイアウトして余白を埋め尽くす
- FillAndExpand: いっぱいに広げて余白を埋め尽くす
まず、Start
, Center
, End
, Fill
を見ていきます。
<?xml version="1.0" encoding="utf-8"?><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"prism:ViewModelLocator.AutowireViewModel="True"x:Class="PrismUnityApp15.Views.MainPage"Title="MainPage"><StackLayout Orientation="Horizontal"><BoxView Color="Red"VerticalOptions="Start" /><BoxView Color="Blue"VerticalOptions="End" /><BoxView Color="Green"VerticalOptions="Center" /><BoxView Color="Aqua"VerticalOptions="Fill" /><!-- Default --></StackLayout></ContentPage>
実行すると以下のようになります。
次にAndExpandがついているオプションについての挙動を見てみます。
<?xml version="1.0" encoding="utf-8"?><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"prism:ViewModelLocator.AutowireViewModel="True"x:Class="PrismUnityApp15.Views.MainPage"Title="MainPage"><StackLayout><BoxView Color="Red"VerticalOptions="StartAndExpand" /><BoxView Color="Blue" /></StackLayout></ContentPage>
実行すると、赤色が上端に配置されて余白を埋め尽くします。そして、青色が赤色が余白を埋め尽くすため下端に表示されます。実行結果を以下に示します。
次に、EndAndExpand
の挙動を確認します。
<?xml version="1.0" encoding="utf-8"?><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"prism:ViewModelLocator.AutowireViewModel="True"x:Class="PrismUnityApp15.Views.MainPage"Title="MainPage"><StackLayout><BoxView Color="Red"VerticalOptions="EndAndExpand" /><BoxView Color="Blue" /></StackLayout></ContentPage>
実行すると、赤色が余白を埋め尽くして下端に表示されます。その下に青色が表示されます。実行結果を以下に示します。
次に、FillAndExpand
の挙動を確認します。
<?xml version="1.0" encoding="utf-8"?><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"prism:ViewModelLocator.AutowireViewModel="True"x:Class="PrismUnityApp15.Views.MainPage"Title="MainPage"><StackLayout><BoxView Color="Red"VerticalOptions="FillAndExpand" /><BoxView Color="Blue" /></StackLayout></ContentPage>
実行すると、赤色が余白を埋め尽くす形でいっぱいに表示されて、残りの部分に青色が表示されます。実行結果を以下に示します。
AndExpandのつくプロパティを複数使用した場合、余白は均等に割り振られます。以下のように2つのコントロールでFillAndExpand
とStartAndExpand
を使用した場合は、上半分に赤色がいっぱいに表示され、下半分の開始位置に青色が配置されます。
<?xml version="1.0" encoding="utf-8"?><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"prism:ViewModelLocator.AutowireViewModel="True"x:Class="PrismUnityApp15.Views.MainPage"Title="MainPage"><StackLayout><BoxView Color="Red"VerticalOptions="FillAndExpand" /><BoxView Color="Blue"VerticalOptions="StartAndExpand"/></StackLayout></ContentPage>
実行結果を以下に示します。
複雑なレイアウト
StackLayout
とLayoutOptions
を組み合わせることで複雑なレイアウトが実現可能です。以下に例を示します。イメージとしてはTwitterクライアントのような見た目をイメージしています。
<?xml version="1.0" encoding="utf-8"?><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"prism:ViewModelLocator.AutowireViewModel="True"x:Class="PrismUnityApp15.Views.MainPage"Title="MainPage"><StackLayout><!-- つぶやき1 --><StackLayout Orientation="Horizontal"VerticalOptions="Start"><BoxView Color="Red" /><StackLayout HorizontalOptions="FillAndExpand"><StackLayout Orientation="Horizontal"><StackLayout Orientation="Vertical"HorizontalOptions="FillAndExpand"><StackLayout Orientation="Horizontal"><Label Text="@okazuki" /><Label Text="かずき@MBPぽちった"HorizontalOptions="FillAndExpand" /></StackLayout><Label Text="XXXXXXXXXXXXXXXXXXXX" /></StackLayout></StackLayout><StackLayout Orientation="Horizontal"HorizontalOptions="EndAndExpand"><Button Text="Like"HorizontalOptions="End" /><Button Text="RT"HorizontalOptions="End" /><Button Text="Quote"HorizontalOptions="End" /></StackLayout></StackLayout></StackLayout><!-- つぶやき2 --><StackLayout Orientation="Horizontal"VerticalOptions="Start"><BoxView Color="Red" /><StackLayout HorizontalOptions="FillAndExpand"><StackLayout Orientation="Horizontal"><StackLayout Orientation="Vertical"HorizontalOptions="FillAndExpand"><StackLayout Orientation="Horizontal"><Label Text="@okazuki" /><Label Text="かずき@MBPぽちった"HorizontalOptions="FillAndExpand" /></StackLayout><Label Text="YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY" /></StackLayout></StackLayout><StackLayout Orientation="Horizontal"HorizontalOptions="EndAndExpand"><Button Text="Like"HorizontalOptions="End" /><Button Text="RT"HorizontalOptions="End" /><Button Text="Quote"HorizontalOptions="End" /></StackLayout></StackLayout></StackLayout></StackLayout></ContentPage>
実行結果を以下に示します。
このように、StackLayout
とLayoutOptions
を組み合わせてネストさせることで、かなりのレイアウトを組むことができます。
Grid
次に、Grid
について説明します。Grid
は、名前の通り格子状にレイアウトの中を区切って、そこにコントロールを配置していきます。行の定義はGrid
のRowDefinitions
プロパティに対してRowDefinition
を追加することで定義できます。列の定義はColumnDefinitions
プロパティに対してColumnDefinition
を追加することで定義できます。デフォルトでは均等に幅と高さが割り振られます。
コントロールの配置はGrid.Row
添付プロパティで行(0オリジン)を指定してGrid.Column
プロパティで列(0オリジン)を指定します。
3x3の格子状に画面を区切った場合のコード例を以下に示します。
<?xml version="1.0" encoding="utf-8"?><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"prism:ViewModelLocator.AutowireViewModel="True"x:Class="PrismUnityApp15.Views.MainPage"Title="MainPage"><Grid><!-- 行の定義 --><Grid.RowDefinitions><RowDefinition /><RowDefinition /><RowDefinition /></Grid.RowDefinitions><!-- 列の定義 --><Grid.ColumnDefinitions><ColumnDefinition /><ColumnDefinition /><ColumnDefinition /></Grid.ColumnDefinitions><BoxView Color="Red" /><!-- デフォルトは0,0に配置される --><BoxView Color="Blue"Grid.Row="0"Grid.Column="1" /><BoxView Color="Aqua"Grid.Row="0"Grid.Column="2" /><BoxView Color="Maroon"Grid.Row="1"Grid.Column="0" /><BoxView Color="Navy"Grid.Row="1"Grid.Column="1" /><BoxView Color="Silver"Grid.Row="1"Grid.Column="2" /><BoxView Color="Purple"Grid.Row="2"Grid.Column="0" /><BoxView Color="Lime"Grid.Row="2"Grid.Column="1" /><BoxView Color="Yellow"Grid.Row="2"Grid.Column="2" /></Grid></ContentPage>
実行結果を以下に示します。
幅と高さの指定
RowDefinition
にはHeight
プロパティで行の高さを指定できます。ColumnDefinition
にはWidth
プロパティで列の幅を指定できます。指定方法には、数字を指定して固定幅を指定する方法と、1*
, 2*
のように*
を使用して余白を占める割合を比率で指定する方法とAuto
を指定して中身のサイズに合わせる方法があります。
コード例を以下に示します。
<?xml version="1.0" encoding="utf-8"?><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"prism:ViewModelLocator.AutowireViewModel="True"x:Class="PrismUnityApp15.Views.MainPage"Title="MainPage"><Grid><!-- 行の定義 --><Grid.RowDefinitions><RowDefinition Height="15" /><!-- 固定 --><RowDefinition Height="1*" /><!-- 余白を1対2に分割 --><RowDefinition Height="2*" /></Grid.RowDefinitions><!-- 列の定義 --><Grid.ColumnDefinitions><ColumnDefinition Width="Auto" /><!-- 中身の幅に応じて設定 --><ColumnDefinition Width="*" /><!-- デフォルト値は*(1*と同じ意味) --><ColumnDefinition /></Grid.ColumnDefinitions><BoxView Color="Red" /><!-- デフォルトは0,0に配置される --><BoxView Color="Blue"Grid.Row="0"Grid.Column="1" /><BoxView Color="Aqua"Grid.Row="0"Grid.Column="2" /><BoxView Color="Maroon"Grid.Row="1"Grid.Column="0" /><BoxView Color="Navy"Grid.Row="1"Grid.Column="1" /><BoxView Color="Silver"Grid.Row="1"Grid.Column="2" /><BoxView Color="Purple"Grid.Row="2"Grid.Column="0" /><BoxView Color="Lime"Grid.Row="2"Grid.Column="1" /><BoxView Color="Yellow"Grid.Row="2"Grid.Column="2" /></Grid></ContentPage>
実行結果を以下に示します。
複数行・複数列の占有
今までは格子状に区切った中の1つのセルに1つのコントロールを置いてきました。Grid
コントロールでは、これに加えて複数のセルにまたがる形でコントロールを配置することができます。Grid.RowSpan
添付プロパティと、Grid.ColumnSpan
添付プロパティを使用することで行の占有数と列の占有数を指定できます。
コード例を以下に示します。
<?xml version="1.0" encoding="utf-8"?><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"prism:ViewModelLocator.AutowireViewModel="True"x:Class="PrismUnityApp15.Views.MainPage"Title="MainPage"><Grid><!-- 行の定義 --><Grid.RowDefinitions><RowDefinition /><RowDefinition /><RowDefinition /></Grid.RowDefinitions><!-- 列の定義 --><Grid.ColumnDefinitions><ColumnDefinition /><ColumnDefinition /><ColumnDefinition /></Grid.ColumnDefinitions><BoxView Color="Red"Grid.RowSpan="2"Grid.ColumnSpan="3"/><BoxView Color="Yellow"Grid.Row="2"Grid.Column="1"Grid.ColumnSpan="2" /></Grid></ContentPage>
実行すると以下のようになります。
複雑なレイアウト
Grid
を使うことで複雑なレイアウトを組むことが簡単にできます。StackLayout
で示した表示と同じような表示をGrid
でもやってみたいと思います。
<?xml version="1.0" encoding="utf-8"?><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"prism:ViewModelLocator.AutowireViewModel="True"x:Class="PrismUnityApp15.Views.MainPage"Title="MainPage"><StackLayout VerticalOptions="Start"><!-- つぶやき1 --><Grid><Grid.RowDefinitions><RowDefinition Height="Auto" /><RowDefinition Height="Auto" /><RowDefinition Height="Auto" /></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="Auto" /><ColumnDefinition /><ColumnDefinition Width="Auto"/><ColumnDefinition Width="Auto"/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions><BoxView Color="Red"Grid.RowSpan="3" /><StackLayout Orientation="Horizontal"Grid.Column="1"Grid.ColumnSpan="4"><Label Text="@okazuki" /><Label Text="かずき@MBPぽちった" /></StackLayout><Label Text="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"Grid.Row="1"Grid.Column="1"Grid.ColumnSpan="4" /><Button Text="Like"Grid.Row="2"Grid.Column="2" /><Button Text="RT"Grid.Row="2"Grid.Column="3" /><Button Text="Quote"Grid.Row="2"Grid.Column="4" /></Grid><!-- つぶやき2 --><Grid><Grid.RowDefinitions><RowDefinition Height="Auto" /><RowDefinition Height="Auto" /><RowDefinition Height="Auto" /></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="Auto" /><ColumnDefinition /><ColumnDefinition Width="Auto"/><ColumnDefinition Width="Auto"/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions><BoxView Color="Red"Grid.RowSpan="3" /><StackLayout Orientation="Horizontal"Grid.Column="1"Grid.ColumnSpan="4"><Label Text="@okazuki" /><Label Text="かずき@MBPぽちった" /></StackLayout><Label Text="YYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"Grid.Row="1"Grid.Column="1"Grid.ColumnSpan="4" /><Button Text="Like"Grid.Row="2"Grid.Column="2" /><Button Text="RT"Grid.Row="2"Grid.Column="3" /><Button Text="Quote"Grid.Row="2"Grid.Column="4" /></Grid></StackLayout></ContentPage>
実行結果を以下に示します。
余白
最後に余白について説明します。余白の設定は、Padding
プロパティとMargin
プロパティがあります。Padding
プロパティがコントロールの外側に余白を設けます。Margin
プロパティがコントロールの内側に余白を設けます。プロパティの設定方法は、4方向に同一の値を設定する方法と、左右と上下にそれぞれ同じ値を設定する方法と、上下左右に個別の値を設定する方法があります。
10
のように単一の値を設定すると上下左右にすべて10の余白が設定されます。10,5
のように2つの値を設定すると左右に10、上下に5の余白が設定されます。5,10,15,20
のように4つの値を設定すると左、上、右、下の順番で余白が設定されます。
コード例を以下に示します。
<?xml version="1.0" encoding="utf-8"?><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"prism:ViewModelLocator.AutowireViewModel="True"x:Class="PrismUnityApp15.Views.MainPage"Title="MainPage"Padding="20"><Grid Margin="10,5"><BoxView Color="Red" /></Grid></ContentPage>
ページのPadding
に20を設定して上下左右に20の余白を持たせています。さらにGridでMargin
を指定して左右に10、上下に5の余白を持たせています。
実行結果を以下に示します。
まとめ
Xamarin.Formsには、いくつかのレイアウトコントロールが定義されていますが、基本的なレイアウトに関していうとStackLayout
とGrid
を組み合わせることで大体実現可能です。まず、とっかかりとしてこの2つのレイアウトコントロールの使い方をマスターして思い通りのページを作れるようになりましょう。