Xamarin.Forms レイアウト(Formsを使用したアプリ作成の次の1歩)

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 レイアウト

アプリの画面を作成する場合、画面上に各種のコントロールを配置していく事になると思いますが、この「配置」をサポートするのが「レイアウト」です。

レイアウトは、ページやビュー上に複数のコントロールを配置するためのコンテナです。

Xamarin.Formsには、7種類のレイアウトクラスがあります。 そして、このうち、複数の子要素を格納できるプロパティーであるChildrenを持つのは、次の4種類です。

  • StackLayout
  • AbsoluteLayout
  • Grid
  • RelativeLayout

残りの3つは、単一の子要素しか格納できないプロパティーであるContentを持つため、1つの子要素を装飾するだけという位置づけになります。

  • Frame
  • ContentView
  • ScrollView

Xamarin Developers Guide 「Xamarin.Forms Layouts」

今回も、可能な限りシンプルなサンプルコードで、この7種類のレイアウトを紹介したいと思います。

(1) StackLayout

iOS Android WindowsPhone
Layout001 Layout002 Layout003

スタックレイアウトは、子要素を縦(デフォルト)または横に並べるレイアウトです。 要素間のスペースは、レイアウト側で指定しますが、余白を全部利用するかどうか(ドッキング状態)は、子要素側のプロパティーで決定されます。

public class App : Application {
    public App() {
       //ラベルを3つ配置したスタックレイヤを生成する
         var stackLayout = new StackLayout {
            Padding = new Thickness(10, Device.OnPlatform(20, 10, 10), 10, 10),
            Spacing = 5, //各要素間のスペース
            Children ={new Label{
                    FontSize=30,
                    Text = "First",
                    HeightRequest=100,// 高さ100
                    BackgroundColor = Color.FromHex("82DADA"),
                },
                new Label{
                    FontSize=30,
                    Text = "Second",
                    VerticalOptions = LayoutOptions.FillAndExpand,//縦方向に余白を最大限利用する
                    BackgroundColor = Color.FromHex("53CF9E"),
                },
                new Label{
                    FontSize=30,
                    Text = "Third",
                    HeightRequest=300,// 高さ300
                    BackgroundColor = Color.FromHex("EB6379"),
                },
            }
        };
        MainPage = new ContentPage {
            Content = stackLayout
        };
    }
}

(2) AbsoluteLayout

iOS Android WindowsPhone
Layout004 Layout005 Layout006

アブソレートレイアウトは、子要素の配置を固定座標で指定するレイアウトです。 指定要領には、範囲指定(Rectangle)、基準座標(Point)の2種類があります。

public class App : Application {
    public App() {

        //アブソレートレイアウトの生成
        var absoluteLayout = new AbsoluteLayout();

        //ラベルの生成とレイアウトへの追加(Rectangle指定)
        var label1 = new Label { Text = "First", BackgroundColor = Color.FromHex("82DADA"), FontSize = 20 };
        absoluteLayout.Children.Add(label1, new Rectangle(20, 20, 200, 200));

        //ラベルの生成とレイアウトへの追加(Point指定)
        var label2 = new Label { Text = "Second", BackgroundColor = Color.FromHex("53CF9E"), FontSize = 20 };
        absoluteLayout.Children.Add(label2, new Point(200, 300));

        //ラベルの生成とレイアウトへの追加(SetLayoutBounds指定)
        var label3 = new Label { Text = "Third", BackgroundColor = Color.FromHex("EB6379"), FontSize = 20 };
        absoluteLayout.Children.Add(label3);
        AbsoluteLayout.SetLayoutBounds(label3, new Rectangle(30, 400, 250, 100));

        MainPage = new ContentPage {
            Content = absoluteLayout
        };
    }
}

(3) Grid

iOS Android WindowsPhone
Layout007 Layout008 Layout009

グリッドは、複数の子要素を、行・列に基づいて配置していくレイアウトです。

public class App : Application {
    public App() {
        //グリッドの生成
        var grid = new Grid {
            Padding = new Thickness(10, Device.OnPlatform(20, 0, 0), 10, 10),//パディング
            RowSpacing = 10, //縦のスペース
            ColumnSpacing = 5, //横のスペース

            RowDefinitions = {//縦に2列
                new RowDefinition { Height = GridLength.Auto },//(高さ)自動調整
                new RowDefinition { Height = new GridLength(100, GridUnitType.Star) }//(高さ)のこり全部
            },
            ColumnDefinitions = {//横に3カラム
                new ColumnDefinition { Width = GridLength.Auto }, //(幅)自動調整
                new ColumnDefinition { Width = new GridLength(100, GridUnitType.Absolute) },//(幅)絶対値
                new ColumnDefinition { Width = new GridLength(10, GridUnitType.Star) }//(幅)のこり全部
            }
        };

        //1列目にラベルを追加
        grid.Children.Add(new Label { Text = "1-1", BackgroundColor = Color.Red, }, 0, 0);//1列目で左から1カラム目
        grid.Children.Add(new Label { Text = "1-2", BackgroundColor = Color.Blue }, 1, 0);//1列目で左から2カラム目
        grid.Children.Add(new Label { Text = "1-3", BackgroundColor = Color.Green }, 2, 0);//1列目で左から3カラム目
        //2列目にラベルを追加
        grid.Children.Add(new Label { Text = "2-1", BackgroundColor = Color.Yellow }, 0, 2, 1, 2); //2列目で左から1~2カラム
        grid.Children.Add(new Label { Text = "2-2", BackgroundColor = Color.Purple }, 2, 1);//2列目で左から3カラム目


        MainPage = new ContentPage {
            Content = grid
        };

    }
}

(4) RelativeLayout

iOS Android WindowsPhone
Layout010 Layout011 Layout012

リラティブレイアウトは、子要素を相対的に配置するレイアウトです。 相対位置の配置方法は、「親を基準に配置する方法」と「別の子要素を基準に配置する方法」の2種類があります。

public class App : Application {
    public App() {
        //リラティブレイアウトの生成
        var relativeLayout = new RelativeLayout();
        //ラベルの追加
        var label1 = new Label { Text = "label1", BackgroundColor = Color.FromHex("82DADA") ,FontSize=60};
        relativeLayout.Children.Add(label1,
            //X座標は、30
            Constraint.Constant(30),
            // Y座標は中央 (親要素との相対位置で配置)                         
            Constraint.RelativeToParent(parent => parent.Height / 2)
        );

        //ラベルの追加
        var label2 = new Label { Text = "label2", BackgroundColor = Color.FromHex("53CF9E"),FontSize=40 };
        relativeLayout.Children.Add(label2,
            //X座標は、100
            Constraint.Constant(100), 
            // Y座標は、label1の20下(他の要素との相対位置で配置)
            Constraint.RelativeToView(label1, (parent, sibling) => sibling.Y + sibling.Height + 20)
         );

       MainPage = new ContentPage {
            Content = relativeLayout
        };
    }
}

(5) ContentView / Frame / ScrollView

iOS Android WindowsPhone
Layout013 Layout014 Layout015

コンテンツビュー、フレーム、スクロールビューは、単一の子要素を扱うレイアウトです。 下記のサンプルは、この3つのレイアウトをスタックレイアウトで縦に並べたものです。

public class App : Application {
    public App() {
        //フレームの生成
        var frame = new Frame {
            //枠線の効果
            OutlineColor = Color.Accent,
            HasShadow = true,
            //ラベルを配置する
            Content = new Label { Text = "Frame" }
        };

        //コンテンツビューの生成
        var contentView = new ContentView {
            BackgroundColor = Color.FromHex("EB6379"),
            Padding = new Thickness(50), //ContentView内での余白
            //ラベルを配置する
            Content = new Label { Text = "ContentView" ,FontSize=20}
        };

        //スクロールビューの生成
        var sb = new StringBuilder(); //100行のテキストを作成
        for (var i = 0; i < 100; i++) {
            sb.Append(string.Format("ScrollView {0}行目\n", i+1));
        }
        var scrollView = new ScrollView {
            VerticalOptions = LayoutOptions.FillAndExpand,
            //ラベルを配置する
            Content = new Label {
                Text = sb.ToString(),
                FontSize = 20,
                TextColor = Color.FromHex("82DADA")
            }
        };

        MainPage = new ContentPage {
            //スタックレイアウトをContentに設定
            Content = new StackLayout {
                Spacing = 10, //要素間のスペース
                Padding = new Thickness(10, Device.OnPlatform(20, 10, 10), 10, 10),
                //作成した「フレーム」・「コンテンツビュー」・「スクロールビュー」を縦に配置する
                Children = { frame, contentView, scrollView }
            }
        };
    }
}

3 まとめ

今回は、コントロールを配置する際に、これをサポートするレイアウトについて紹介しました。 レイアウトは、プラットフォームごとの違いが少ないので、比較的違和感が少ないのでは無いでしょうか。

最初に紹介した「ページ」を生成し、そのページ上で今回紹介したのレイアウトが利用できれば、後は色々なコントロールを配置する事でXamarin.Formsの画面が出来上がります。

次回は、各種のコントロールについて紹介したいと思います。

githubサンプルコード(https://github.com/furuya02/Xamarin.Forms.LayoutSample)

本記事は、2015年10月24日現在で最新の Xamarin.Forms 1.5.1.6471 を使用して作成されています。

4 参考リンク


Xamarin.Forms Layouts
この辺でXamarin導入による 効果と限界をしっかり把握してみよう MVP Community Camp 2015
Xamarin記事一覧(SAPPOROWORKSの覚書)