Xamarin.Forms:コントロールを等間隔に配置するには?.NET TIPS

Xamarin.Formsアプリでは、StackLayout/Gridコントロールとそれらのプロパティを使うことで、とても簡単にコントロールを等間隔に配置できる。

» 2016年09月14日 05時00分 公開
[山本康彦BluewaterSoft/Microsoft MVP for Windows Development]
「.NET TIPS」のインデックス

連載目次

対象:Visual Studio 2015以降


 Xamarin.Formsは、XAMLとC#を使ってAndroid/iOS/Windows向けのクロスプラットフォーム開発を行える開発環境だ。

 画面上の決められた領域の中でコントロールを等間隔に配置するには、どうしたらよいだろうか? もちろんGridコントロールを使って、その行/列のサイズを細かく調整していけば実現できるだろう。だが、Xamarin.Formsにはもっと簡単な方法があるのだ。本稿ではその方法を解説する。

等間隔に配置する2通りのパターン

 コントロールを等間隔に並べるといっても、2通りのパターンがある(次の画像)。コントロールのサイズを一定にするか、間隔を一定にするかだ。

コントロールを等間隔で縦1列に配置する2通りのパターン コントロールを等間隔で縦1列に配置する2通りのパターン
これはWindows 10(PC)で実行している。
画像左側のウィンドウの高さを大きくすると、右側のウィンドウになる。ウィンドウの左側では、黄色いコントロールの高さを一定に保ったまま、コントロール間の間隔が変化する。ウィンドウの右側では、黄色いコントロールの高さが変化し、コントロール間の間隔は一定のままだ。

 縦1列(または横1列)に並べたコントロールのサイズを保ったまま間隔を可変とするには、StackLayoutコントロール(Xamarin.Forms名前空間)が利用できる。次に説明する。

 間隔を一定に保ったままコントロールのサイズを可変にするのは、Gridコントロール(Xamarin.Forms名前空間)で簡単に実現できる。こちらは後で説明する。

コントロールのサイズを保って等間隔に配置するには?

 StackLayoutコントロールを使い、StackLayoutコントロール用の特別な値をその内部に置いたコントロールのVerticalOptionsプロパティに設定するとよい。

 コントロールのVerticalOptionsプロパティに設定できるLayoutOptions構造体(Xamarin.Forms名前空間)には、以下に示す4つの特別な値がある。これらは、StackLayoutコントロール内に配置したコントロールだけで有効だ。

  • StartAndExpand: 縦並びではコントロールの下に(横並びでは右に)間隔を開ける
  • CenterAndExpand: 縦並びではコントロールの上下に(横並びでは左右に)間隔を開ける
  • EndAndExpand: 縦並びではコントロールの上に(横並びでは左に)間隔を開ける
  • FillAndExpand: 縦並びではコントロールを上下に(横並びでは左右に)拡張する*1

*1 FillAndExpandを指定すると、間隔が一定になる(StackLayoutコントロールのSpacingプロパティに設定した値になる)。間隔を一定に保ったままコントロールのサイズを可変とするには、後で説明するGridコントロールによる方法の他に、このFillAndExpandを使ってもよい。


 コントロールのサイズを保って等間隔に配置するには、1つ目のコントロールのVerticalOptionsプロパティにはStartを指定し、残りのコントロールのVerticalOptionsプロパティにはEndAndExpandを指定する(次のコード)。1つ目のコントロールにもEndAndExpandを指定してしまうと、その上にもすき間が開いてしまうので注意しよう。

<StackLayout Padding="30">
  <StackLayout.Resources>
    <ResourceDictionary>
      <Style TargetType="Frame">
        <!-- それぞれのFrameコントロールの上に間隔を均等に配置 -->
        <Setter Property="VerticalOptions" Value="EndAndExpand" />
        <Setter Property="OutlineColor" Value="Accent" />
      </Style>
    </ResourceDictionary>
  </StackLayout.Resources>

  <!-- 最初のFrameコントロールだけは、余白なしにする -->
  <Frame VerticalOptions="Start"><Label>AAA</Label></Frame>
  <!-- 以降のFrameコントロールにはStyleで定義したEndAndExpandが適用される -->
  <Frame><Label>BBB</Label></Frame>
  <Frame><Label>CCC</Label></Frame>
  <Frame><Label>DDD</Label></Frame>
</StackLayout>

コントロールのサイズを保って等間隔に配置する例(XAML)
これで冒頭の画像のウィンドウの左側に近いレイアウトになる。サンプルが簡潔になるように細部を省略してあるので、冒頭の画像と同じにはならない(完全なコードは最後に紹介する)。
なお、Frameコントロール(Xamarin.Forms名前空間)の意味合いが、WPFアプリ/UWPアプリの同名コントロールとはずいぶん違う。WPFアプリ/UWPアプリのBorderコントロールに近いものだ。

間隔を一定に保って等間隔に配置するには?

 StackLayoutコントロールでFillAndExpandを指定してもよいが、GridコントロールのRowSpacingプロパティ/ColumnSpacingプロパティを使っても簡単にできる。縦並びのときはRowSpacingプロパティを設定する(次のコード)。

<Grid RowSpacing="10" Padding="30">
  <Grid.Resources>
    <ResourceDictionary>
      <Style TargetType="Frame">
        <Setter Property="OutlineColor" Value="Accent" />
      </Style>
    </ResourceDictionary>
  </Grid.Resources>
  <Grid.RowDefinitions>
    <RowDefinition Height="*" />
    <RowDefinition Height="*" />
    <RowDefinition Height="*" />
    <RowDefinition Height="*" />
  </Grid.RowDefinitions>

  <Frame><Label>000</Label></Frame>
  <Frame Grid.Row="1"><Label>111</Label></Frame>
  <Frame Grid.Row="2"><Label>222</Label></Frame>
  <Frame Grid.Row="3"><Label>333</Label></Frame>
</Grid>

間隔を一定に保って等間隔に配置する例(XAML)
これで冒頭の画像のウィンドウの右側に近いレイアウトになる。サンプルが簡潔になるように細部を省略してあるので、冒頭の画像と同じにはならない(完全なコードは次に紹介する)。
なお、このようにGridコントロールを均等に分割する(全ての<RowDefinition>要素でHeight="*"とする)場合には、<Grid.RowDefinitions>要素は省略できる。

実際の例

 実際の例として、冒頭の画像で紹介した画面のXAMLコードを示しておこう。

 ソリューションを新しく作るときに[Blank Xaml App (Xamarin.Forms Portable)]を選ぶ。そのPCLプロジェクトにあるMainPage.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:local="clr-namespace:dotNetTips1158"
             x:Class="dotNetTips1158.MainPage">
  <!--<Label Text="Welcome to Xamarin Forms!"
           VerticalOptions="Center"
           HorizontalOptions="Center" />-->
  <ContentPage.Padding>
    <OnPlatform x:TypeArguments="Thickness" iOS="0,20,0,0" />
  </ContentPage.Padding>
  <Grid ColumnSpacing="20">
    <!-- 均等分割なら、ColumnDefinitionsは省略可能 -->
    <!--<Grid.ColumnDefinitions>
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>-->
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <!-- 以降が均等分割だけなら、以降のRowDefinitionを省略可能 -->
      <!--<RowDefinition Height="*" />-->
    </Grid.RowDefinitions>
    <Label Text="StackLayout" HorizontalOptions="Center" VerticalOptions="Center" />

    <!-- 【画面左側】コントロールのサイズを保って等間隔に配置する -->
    <StackLayout Grid.Row="1" BackgroundColor="#2200ff00" Padding="10">
      <StackLayout.Resources>
        <ResourceDictionary>
          <Style TargetType="Frame">
            <!-- それぞれのFrameコントロールの上に間隔を均等に配置 -->
            <Setter Property="VerticalOptions" Value="EndAndExpand" />
            <Setter Property="BackgroundColor" Value="Yellow" />
            <Setter Property="OutlineColor" Value="Green" />
          </Style>
          <Style TargetType="Label">
            <Setter Property="FontAttributes" Value="Bold" />
            <Setter Property="HorizontalTextAlignment" Value="Center" />
            <Setter Property="TextColor" Value="Black" />
          </Style>
        </ResourceDictionary>
      </StackLayout.Resources>

      <!-- 最初のコントロールだけは、余白なしにする -->
      <Frame VerticalOptions="Start"><Label>AAA</Label></Frame>

      <Frame><Label>BBB</Label></Frame>
      <Frame><Label>CCC</Label></Frame>
      <Frame><Label>DDD</Label></Frame>
    </StackLayout>

    <Label Grid.Column="1" Text="Grid"
           HorizontalOptions="Center" VerticalOptions="Center" />

    <!-- 【画面右側】間隔を一定に保って等間隔に配置する -->
    <Grid Grid.Row="1" Grid.Column="1" BackgroundColor="#2200ffff"
          RowSpacing="10" Padding="10">
      <Grid.Resources>
        <ResourceDictionary>
          <Style TargetType="Frame">
            <Setter Property="BackgroundColor" Value="Yellow" />
            <Setter Property="OutlineColor" Value="Blue" />
          </Style>
          <Style TargetType="Label">
            <Setter Property="FontAttributes" Value="Bold" />
            <Setter Property="HorizontalTextAlignment" Value="Center" />
            <Setter Property="VerticalTextAlignment" Value="Center" />
            <Setter Property="TextColor" Value="Black" />
          </Style>
        </ResourceDictionary>
      </Grid.Resources>
      <!-- 均等分割なら、RowDefinitionsは省略可能 -->
      <!--<Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
      </Grid.RowDefinitions>-->

      <Frame><Label>000</Label></Frame>
      <Frame Grid.Row="1"><Label>111</Label></Frame>
      <Frame Grid.Row="2"><Label>222</Label></Frame>
      <Frame Grid.Row="3"><Label>333</Label></Frame>
    </Grid>
  </Grid>
</ContentPage>

コントロールを等間隔に配置するサンプルコード(XAML)
自動生成されたLabelコントロールをコメントアウトし、<ContentPage.Padding>要素以降を追加した。
これが冒頭に示した画面のソースコードである。
なお、Gridコントロールを使うときに記述が面倒な行/列の定義であるが、Xamarin.Formsでは推論可能な行/列の定義は省略できる。

 モバイル端末での実行結果は、次の画像のようになる。

Visual Studio Emulator for Androidでの実行結果
iOS Simulator for Windowsでの実行結果
Mobile Emulator(Windows 10)での実行結果 実行結果
上はVisual Studio Emulator for Androidでの実行結果。中はiOS Simulator for Windowsでの実行結果。下はMobile Emulator(Windows 10)での実行結果。なお、iOS Simulator for Windowsは本稿執筆段階でプレビュー段階となっている。使用方法については「XamarinアプリのMacでのビルドとiOS Simulator for Windows」を参照されたい。

まとめ

 Xamarin.FormsのXAMLには、WPF/UWPのXAMLにはなかったレイアウト用の便利な機能がある。今回はその中から次の3点を紹介した。

  • StackLayoutコントロールの子コントロールで使える「〜AndExpand」という位置指定
  • GridコントロールのRowSpacingプロパティ/ColumnSpacingプロパティ
  • Gridコントロールで行定義/列定義を省略できる

利用可能バージョン:Visual Studio 2015以降
カテゴリ:Xamarin 処理対象:Xamarin.Forms
関連TIPS:Xamarin.Forms:プロジェクトにXamlページを追加するには?
関連TIPS:Xamarin.Forms:プラットフォームに応じて画面の一部を変えるには?


「.NET TIPS」のインデックス

.NET TIPS

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。