C#Xamarin.Formsでスマホ開発#13 MasterDetailPageの作り方

当サイトではアフィリエイト広告を利用しています。

Xamarin.Formsでスマホアプリ開発

MasterDetailPageとは?

MasterDetailPageとは,画面の左側の端から右方向にスワイプして表示するページの事です。Androidなどでは,左側をスワイプしてGoogleのニュースを表示したりできますが,その要領で表示するページの事です。この左から出てくるページを「マスター」,最初から表示されているメインのページを「ディティール」と呼び,この2つの関係性を持つページをMasterDetailPageと呼んでいます。マスターページはメインページから以外でも表示することができるので,どんなページが表示されていても,いつでも設定変更を行いたい項目や,いつでも見られるようにしておきたい機能などを置いておくことで,使い勝手の良いアプリケーションを作成することができます。使い方しだいで結構いろんなことができるのではないでしょうか。あなたもこの機能を使って,いい感じの仕様を考えてみてください。

左端からスワイプをするか,ハンバーガーボタンを押下すると,マスターページが表示される。

MasterDetailPageの作り方

あたらしいプロジェクトの作成

まずは新しいXamarin.Formsのプロジェクトを作成してください。今回はAndroidとUWPのプロジェクトを作成します。ソリューションの名前は「XSample」にします。

MainPage.xamlの編集

プロジェクトを作成すると自動的にMainPage.xamlというページが作成されます。今回はこれをMasterDetailPageに変更します。

<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XSample"
             x:Class="XSample.MainPage">

    <MasterDetailPage.Master>
        <ContentPage Title="Master">
            <StackLayout>
                <Button Text="AAA"/>
                <Button Text="BBB"/>
            </StackLayout>
        </ContentPage>
    </MasterDetailPage.Master>

    <MasterDetailPage.Detail>
        
    </MasterDetailPage.Detail>
  

</MasterDetailPage>

MasterDetailPageに変更する手順

  • MasterDetailPageにする場合は「ContentPage」になっている部分をMasterDetailPageに変更します。
  • デフォルトで作成されているLabelを削除してください。ようこそXamarinForms的なラベルの事です。
  • MasterDetailPageはMasterとMasterDetailPage.Detailで構成します。Masterの方がマスターページなので,横から出てくる方の画面です。Detailが最初から表示されている方の画面です。
  • MasterにContentPageを定義しTitleに任意の文言を入れます。これがないとなぜかエラーとなります。その次のStackLayoutの部分はマスターページに表示したいコントロールを定義します。ここではAAAとBBBのボタンを2つ並べています。
  • Detailを定義します。この中にContentPageを作成しても構いませんが,別のファイルに定義して,コードビハインドでそのページを設定することができるので,今回はそのようにします。

以上でContentPageをMasterDetailPageにする手順となります。

MenuPageの作成

それではMasterDetailPageのDetailに設定するためのメインのページを作成しましょう。今回は最初にメニューページを表示して,そこにマスターページが表示されるという構成にしたいと思います。MenuPageというページを作成しますが,プロジェクトにそのままページを追加すると,どこにどんなファイルがるかが分かりづらくなるため「Pages」というフォルダーを作成してそこにPage関係のすべてを追加していくことにします。どのような場合もフォルダー分けやプロジェクトの分け方は大事です。人間は階層と名前で判断しますから,階層分けと名前の付け方はプログラムをするうえで重要な工程となります。とにかく今回は「Pages」というフォルダーを作成して「MenuPage」というページを作成します。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XSample.Pages.MenuPage">
    <ContentPage.Content>
        <StackLayout>
            <Label Text="MenuPage!"
                VerticalOptions="CenterAndExpand" 
                HorizontalOptions="CenterAndExpand" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
  • デフォルトで作成される「ようこそラベル」のTextを「MenuPage!」に変更します。

MainPageのDetailを設定

MainPage.xamlのMasterDetailPage.Detailを設定していませんでしたね。今回作成したMenuPageをそのDetailとして設定します。これでMenuPageが初期起動され,よこから引っ張るとマスターページとしてMainPageのMasterエリアで設定したページが表示されるようになります。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using XSample.Pages;

namespace XSample
{
    public partial class MainPage : MasterDetailPage
    {
        public MainPage()
        {
            InitializeComponent();

            this.Detail = new NavigationPage(new MenuPage());
        }
    }
}
  • MainPageはもともと「ContentPage」として実装されていたのでコードビハインド側も「ContentPage」が継承されています。ここをMasterDetailPageに変更します。
  • コンストラクタでMenuPageをDetailに設定します。このthisDetailがXaml側のDetailの事になります。これでMasterとDetailが設定できたことになります。

実行

この状態で一度実行してみましょう。Androidが表示されたら左端からスワイプしてマスターページが表示されるか確認しましょう。うまく実装できていたらマスターページが表示されるはずです。UWPは,はじめからマスターページが表示されています。これでは意図している動きではないため修正が必要です。

MasterBehavior

UWPでマスターページが最初から表示されている問題はMasterBehaviorで調整できます。

<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XSample"
             x:Class="XSample.MainPage"
             MasterBehavior="Popover">

    <MasterDetailPage.Master>
        <ContentPage Title="Master">
            <StackLayout>
                <Button Text="AAA"/>
                <Button Text="BBB"/>
            </StackLayout>
        </ContentPage>
    </MasterDetailPage.Master>

    <MasterDetailPage.Detail>
        
    </MasterDetailPage.Detail>
  

</MasterDetailPage>
  • MasterDetailPage のエリアにMasterBehavior=”Popover”と記述することで,マスターページは非表示で起動するようになります。

NextPageの追加

現在はMenuPageからマスターページを表示していますが,MenuPageから遷移した画面からでもマスターページを表示することができます。そのことを実感するために,もう一つページを作り,MainPageからそのページを呼びだし,実際にそのページからもマスターページを表示できるかどうかを確認してみましょう。呼び出すページはNextPageという名前で新規で作成しましょう。例のごとくPagesというフォルダーの中にページは作成します。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XSample.Pages.NextPage">
    <ContentPage.Content>
        <StackLayout>
            <Label Text="NextPage!"
                VerticalOptions="CenterAndExpand" 
                HorizontalOptions="CenterAndExpand" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
  • 作成したページのようこそラベルのテキストを「NextPage!」に変更します。

MenuPageにNextButtonを作成

MenuPageにボタンを追加して,今作成したNextPageを呼び出しましょう。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XSample.Pages.MenuPage">
    <ContentPage.Content>
        <StackLayout>
            <Label Text="MenuPage!"
                VerticalOptions="CenterAndExpand" 
                HorizontalOptions="CenterAndExpand" />
            <Button Text="NextPage"
                    Clicked="Button_Clicked"/>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
  • MenuPageにボタンを追加
  • TextをNextPage
  • クリックイベントを作成
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace XSample.Pages
{
	[XamlCompilation(XamlCompilationOptions.Compile)]
	public partial class MenuPage : ContentPage
	{
		public MenuPage ()
		{
			InitializeComponent ();
		}

        private void Button_Clicked(object sender, EventArgs e)
        {
            Navigation.PushAsync(new NextPage());
        }
    }
}
  • 作成されたクリックイベントからNextPageを呼び出し

NextPageからもマスターページが表示できる

実行するとMainPageからは当然マスターページが表示できますが,「NextPage」を選択し,表示されたNextPageの左端からスワイプしても同じマスターページが表示されることが確認できると思います。そのため,いつでも設定を変えたいようなものや,常に確認したいような値の画面などにすることで,非常に便利な機能となると思います。使い方は発想次第で色々使えると思います。

サンプルコード全体

<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XSample"
             x:Class="XSample.MainPage"
             MasterBehavior="Popover">

    <MasterDetailPage.Master>
        <ContentPage Title="Master">
            <StackLayout>
                <Button Text="AAA"/>
                <Button Text="BBB"/>
            </StackLayout>
        </ContentPage>
    </MasterDetailPage.Master>

    <MasterDetailPage.Detail>
        
    </MasterDetailPage.Detail>
  

</MasterDetailPage>
using Xamarin.Forms;
using XSample.Pages;

namespace XSample
{
    public partial class MainPage : MasterDetailPage
    {
        public MainPage()
        {
            InitializeComponent();

            this.Detail = new NavigationPage(new MenuPage());
        }
    }
}
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XSample.Pages.MenuPage">
    <ContentPage.Content>
        <StackLayout>
            <Label Text="MenuPage!"
                VerticalOptions="CenterAndExpand" 
                HorizontalOptions="CenterAndExpand" />
            <Button Text="NextPage"
                    Clicked="Button_Clicked"/>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
namespace XSample.Pages
{
	[XamlCompilation(XamlCompilationOptions.Compile)]
	public partial class MenuPage : ContentPage
	{
		public MenuPage ()
		{
			InitializeComponent ();
		}

        private void Button_Clicked(object sender, EventArgs e)
        {
            Navigation.PushAsync(new NextPage());
        }
    }
}
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XSample.Pages.NextPage">
    <ContentPage.Content>
        <StackLayout>
            <Label Text="NextPage!"
                VerticalOptions="CenterAndExpand" 
                HorizontalOptions="CenterAndExpand" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace XSample.Pages
{
	[XamlCompilation(XamlCompilationOptions.Compile)]
	public partial class NextPage : ContentPage
	{
		public NextPage ()
		{
			InitializeComponent ();
		}
	}
}