Xamarin.Forms の TabbedPage

Xamarin.Forms の TabbedPage は、タブのリストと大きな詳細エリアで構成されており、各タブでは、コンテンツが詳細エリアに読み込まれます。 次のスクリーンショットは、iOS と Android での TabbedPage を示しています。

iOS と Android 上の 3 つのタブを含む TabbedPage のスクリーンショット

iOS では、タブのリストが画面の下部に表示され、その上に詳細エリアが表示されます。 各タブは、タイトルとアイコンで構成されます。これは、アルファ チャネルを含む PNG ファイルです。 縦長の向きでは、タブ バーのアイコンがタブ タイトルの上に表示されます。 横長の向きでは、アイコンとタイトルが横に並んで表示されます。 また、デバイスと向きに応じて、ノーマルまたはコンパクトなタブ バーが表示される場合があります。 6 個以上のタブがある場合、[その他] タブが表示され、これを使用して追加のタブにアクセスできます。

Android では、タブのリストが画面の上部に表示され、その下に詳細エリアが表示されます。 各タブは、タイトルとアイコンで構成されます。これは、アルファ チャネルを含む PNG ファイルです。 タブは、プラットフォーム固有で画面の下部に移動できます。 6 個以上のタブがあり、画面の下部にタブ リストがある場合、[その他] タブが表示され、これを使用して追加のタブにアクセスできます。 アイコン要件の詳細については、material.io のタブに関するページと、developer.android.com の「各種のセル密度をサポートする」を参照してください。 タブを画面の下部に移動する方法については、TabbedPage ツール バーの配置と色の設定に関する記事を参照してください。

Universal Windows Platform (UWP) では、タブのリストが画面の上部に表示され、その下に詳細エリアが表示されます。 各タブは、タイトルで構成されます。 ただし、各タブにはプラットフォーム固有のアイコンを追加できます。 詳細については、「Windows 上の TabbedPage アイコン」を参照してください。

ヒント

スケーラブル ベクター グラフィック (SVG) ファイルは、TabbedPage にタブ アイコンとして表示することができます。

  • iOS の TabbedRenderer クラスには、指定されたソースからタブ アイコンを読み込むために使用できるオーバーライド可能な GetIcon メソッドがあります。 さらに、必要に応じて、アイコンの選択バージョンと未選択バージョンも提供することができます。
  • Android AppCompat の TabbedPageRenderer クラスには、カスタム Drawable からタブ アイコンを読み込むために使用できるオーバーライド可能な SetTabIconImageSource メソッドがあります。 また、SVG ファイルをベクター ドローアブル リソースに変換して、Xamarin.Forms で自動的に表示されるようにすることもできます。 SVG ファイルをドローアブル リソースに変換する方法の詳細については、developer.android.com にある 「さまざまな密度に適用可能なベクター グラフィックの追加」を参照してください。

TabbedPage を作成する

TabbedPage を作成するには、次の 2 つの方法を使用することができます。

どちらの方法を使用する場合も、ユーザーが各タブを選択すると、TabbedPage に各ページが表示されます。

重要

TabbedPageNavigationPage インスタンスおよび ContentPage インスタンスのみで作成することをお勧めします。 こうすることにより、すべてのプラットフォームで一貫したユーザー エクスペリエンスを提供することができます。

また、TabbedPage では次のプロパティが定義されます。

これらのプロパティはすべて、BindableProperty オブジェクトを基盤としています。つまり、スタイルを指定でき、プロパティがデータ バインディングの対象になる場合があります。

警告

TabbedPage では、TabbedPage の構築時に各 Page オブジェクトが作成されます。 これにより、特に TabbedPage がアプリケーションのルート ページである場合に、ユーザー エクスペリエンスが低下する可能性があります。 ただし、Xamarin.Forms シェルを使用すると、ナビゲーションに応じて、タブ バーを介してアクセスされるページをオン デマンドで作成できます。 詳細は、「Xamarin.Forms シェル」を参照してください。

ページ コレクションを使って TabbedPage を作成する

Page オブジェクトのコレクション (ContentPage オブジェクトのコレクションなど) を使って TabbedPage を作成できます。 これは、Page オブジェクトを TabbedPage.Children コレクションに追加することで実現されます。 XAML では次のようにしてこれが実現されます。

<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            xmlns:local="clr-namespace:TabbedPageWithNavigationPage;assembly=TabbedPageWithNavigationPage"
            x:Class="TabbedPageWithNavigationPage.MainPage">
    <local:TodayPage />
    <NavigationPage Title="Schedule" IconImageSource="schedule.png">
        <x:Arguments>
            <local:SchedulePage />
        </x:Arguments>
    </NavigationPage>
</TabbedPage>

Note

TabbedPage の派生元である、MultiPage<T> クラスの Children プロパティは、MultiPage<T>ContentProperty です。 そのため、XAML では、Page オブジェクトを Children プロパティに明示的に割り当てる必要はありません。

同等の C# コードを次に示します。

public class MainPageCS : TabbedPage
{
  public MainPageCS ()
  {
    NavigationPage navigationPage = new NavigationPage (new SchedulePageCS ());
    navigationPage.IconImageSource = "schedule.png";
    navigationPage.Title = "Schedule";

    Children.Add (new TodayPageCS ());
    Children.Add (navigationPage);
  }
}

この例では、TabbedPage に 2 つの Page オブジェクトが設定されています。 最初の子は ContentPage オブジェクトで、2 番目の子は、ContentPage オブジェクトを含む NavigationPage です。

次のスクリーンショットは、TabbedPage 内の ContentPage オブジェクトを示しています。

iOS と Android 上の 3 つのタブを含む TabbedPage のスクリーンショット

別のタブを選択すると、タブを表す ContentPage オブジェクトが表示されます。

iOS と Android 上のタブを含む TabbedPage のスクリーンショット

[スケジュール] タブで、ContentPage オブジェクトが NavigationPage オブジェクト内にラップされます。

警告

NavigationPageTabbedPage に配置することはできますが、TabbedPageNavigationPage に配置することはお勧めしません。 これは、iOS では、UITabBarController が常に UINavigationController のラッパーとして機能するためです。 詳細については、iOS 開発者ライブラリの「Combined View Controller Interfaces」 (View Controller インターフェイスの結合) を参照してください。

ナビゲーションは、ContentPage オブジェクトが NavigationPage オブジェクト内にラップされている場合に、タブ内で実行できます。 これを行うには、ContentPage オブジェクトの Navigation プロパティに対して PushAsync メソッドを呼び出します。

await Navigation.PushAsync (new UpcomingAppointmentsPage ());

移動先のページは、PushAsync メソッドへの引数として指定されます。 この例では、UpcomingAppointmentsPage ページがナビゲーション スタックにプッシュされるようになり、そこがアクティブ ページとなります。

iOS および Android 上のタブ内のナビゲーションのスクリーンショット

NavigationPage クラスを使用してナビゲーションを実行する方法の詳細については、「階層ナビゲーション」を参照してください。

テンプレートを使って TabbedPage を作成する

データのコレクションを ItemsSource プロパティに割り当て、データを Page オブジェクトとしてテンプレート化する ItemTemplate プロパティに DataTemplate オブジェクトを割り当てることにより、TabbedPage を作成できます。 XAML では次のようにしてこれが実現されます。

<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:TabbedPageDemo;assembly=TabbedPageDemo"
            x:Class="TabbedPageDemo.TabbedPageDemoPage"
            ItemsSource="{x:Static local:MonkeyDataModel.All}">            
  <TabbedPage.Resources>
    <ResourceDictionary>
      <local:NonNullToBooleanConverter x:Key="booleanConverter" />
    </ResourceDictionary>
  </TabbedPage.Resources>
  <TabbedPage.ItemTemplate>
    <DataTemplate>
      <ContentPage Title="{Binding Name}" IconImageSource="monkeyicon.png">
        <StackLayout Padding="5, 25">
          <Label Text="{Binding Name}" Font="Bold,Large" HorizontalOptions="Center" />
          <Image Source="{Binding PhotoUrl}" WidthRequest="200" HeightRequest="200" />
          <StackLayout Padding="50, 10">
            <StackLayout Orientation="Horizontal">
              <Label Text="Family:" HorizontalOptions="FillAndExpand" />
              <Label Text="{Binding Family}" Font="Bold,Medium" />
            </StackLayout>
            ...
          </StackLayout>
        </StackLayout>
      </ContentPage>
    </DataTemplate>
  </TabbedPage.ItemTemplate>
</TabbedPage>

同等の C# コードを次に示します。

public class TabbedPageDemoPageCS : TabbedPage
{
  public TabbedPageDemoPageCS ()
  {
    var booleanConverter = new NonNullToBooleanConverter ();

    ItemTemplate = new DataTemplate (() =>
    {
      var nameLabel = new Label
      {
        FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label)),
        FontAttributes = FontAttributes.Bold,
        HorizontalOptions = LayoutOptions.Center
      };
      nameLabel.SetBinding (Label.TextProperty, "Name");

      var image = new Image { WidthRequest = 200, HeightRequest = 200 };
      image.SetBinding (Image.SourceProperty, "PhotoUrl");

      var familyLabel = new Label
      {
        FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
        FontAttributes = FontAttributes.Bold
      };
      familyLabel.SetBinding (Label.TextProperty, "Family");
      ...

      var contentPage = new ContentPage
      {
        IconImageSource = "monkeyicon.png",
        Content = new StackLayout {
          Padding = new Thickness (5, 25),
          Children =
          {
            nameLabel,
            image,
            new StackLayout
            {
              Padding = new Thickness (50, 10),
              Children =
              {
                new StackLayout
                {
                  Orientation = StackOrientation.Horizontal,
                  Children =
                  {
                    new Label { Text = "Family:", HorizontalOptions = LayoutOptions.FillAndExpand },
                    familyLabel
                  }
                },
                // ...
              }
            }
          }
        }
      };
      contentPage.SetBinding (TitleProperty, "Name");
      return contentPage;
    });
    ItemsSource = MonkeyDataModel.All;
  }
}

この例では、各タブは、Image および Label オブジェクトを使用してタブのデータを表示する ContentPage オブジェクトで構成されています。

iOS と Android 上のテンプレート化された TabbedPage のスクリーンショット

別のタブを選択すると、タブを表す ContentPage オブジェクトが表示されます。