Xamarin.Forms TabbedPage

Download Sample下载示例

它 Xamarin.FormsTabbedPage 包含选项卡列表和更大的详细信息区域,每个选项卡将内容加载到详细信息区域。 以下屏幕截图显示 iOS 和 Android 上的 TabbedPage

Screenshot of a TabbedPage containing three tabs, on iOS and Android

在 iOS 上,选项卡的列表显示在屏幕的底部,而详细信息区域显示在上方。 每个选项卡都包含一个标题和一个图标,该图标应为带有 alpha 通道的 PNG 文件。 如以纵向显示,选项卡栏图标位于选项卡标题上方。 如以横向显示,图标与标题并排显示。 此外,根据设备和方向,选项卡栏或显示为标准版或显示为缩减版。 如果有五个以上的选项卡,会显示“更多”选项卡,可用于访问其他选项卡

在 Android 上,选项卡列表显示在屏幕顶部,详细信息区域显示在下方。 每个选项卡都包含一个标题和一个图标,该图标应为带有 alpha 通道的 PNG 文件。 但是,可以使用特定于平台的操作将选项卡移动至屏幕底部。 如果有五个以上的选项卡,且选项卡列表位于屏幕底部,会显示“更多”选项卡,可用于访问其他选项卡。 有关图标要求的信息,请参阅 material.io 上的选项卡和 developer.android.com 上的支持不同的像素密度。 有关将选项卡移动到屏幕底部的信息,请参阅设置 TabbedPage 工具栏位置和颜色

在通用 Windows 平台 (UWP) 上,选项卡列表显示在屏幕顶部,详细信息区域显示在下方。 每个选项卡都包含一个标题。 但是,可以使用特定于平台布局向每个选项卡添加图标。 有关详细信息,请参阅 Windows 上的 TabbedPage 图标

提示

可缩放矢量图形 (SVG) 文件可在 TabbedPage 中显示为选项卡图标:

  • iOS TabbedRenderer 类具有可替代的 GetIcon 方法,可用于从指定的源加载选项卡图标。 此外,必要时可提供选定和未选定版本的图标。
  • Android AppCompat TabbedPageRenderer 类具有可替代的 SetTabIconImageSource 方法,可用于从自定义 Drawable 加载选项卡图标。 或者,SVG 文件可转换为矢量可绘制资源,它们可由 Xamarin.Forms 自动显示。 若要详细了解如何将 SVG 文件转换为矢量可绘制资源,请参阅 developer.android.com 上的添加多密度矢量图形

有关详细信息,请参阅带有 SVG 选项卡图标的 Xamarin.Forms TabbedPage

创建 TabbedPage

可以使用两种方法创建 TabbedPage

使用这两种方法,TabbedPage 将在用户选择每个标签时显示每个页面。

重要

建议仅使用 NavigationPageContentPage 实例填充 TabbedPage。 这将有助于确保在所有平台上都有一致的用户体验。

此外,TabbedPage 定义以下属性:

所有这些属性都由 BindableProperty 对象提供支持,这意味着可设置他们的样式,并且这些属性可以作为数据绑定的目标。

警告

TabbedPage 中,每个 TabbedPage 对象在构造 Page 时创建。 这可能会导致用户体验不佳,尤其是在 TabbedPage 是应用程序的根页面时。 但是,Xamarin.Forms Shell 可以根据需要创建通过选项卡栏访问的页面,以响应导航。 有关详细信息,请参阅 Xamarin.Forms Shell

使用页集合填充 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>

注意

派生出 TabbedPageMultiPage<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);
  }
}

在此示例中,使用了两个 Page 对象填充 TabbedPage。 第一个子级是 ContentPage 对象,第二个子级是包含 ContentPage 对象的 NavigationPage

以下屏幕截图显示 TabbedPage 中的 ContentPage 对象:

Screenshot of a TabbedPage containing three tabs, on iOS and Android

选择另一个选项卡将显示表示该选项卡的 ContentPage 对象:

Screenshot of a TabbedPage containing tabs, on iOS and Android

在“计划”选项卡上,ContentPage 对象包装在 NavigationPage 对象中。

警告

虽然 NavigationPage 可以放置在 TabbedPage 中,但不建议将 TabbedPage 放置到 NavigationPage 中。 这是因为,在 iOS 上,UITabBarController 始终充当 UINavigationController 的包装器。 有关详细信息,请参阅 iOS 开发人员库中的组合的视图控制器接口

导航可以在选项卡中执行,前提是 ContentPage 对象包装在 NavigationPage 对象中。 可以通过在 ContentPage 对象的 Navigation 属性上调用 PushAsync 方法来实现此操作:

await Navigation.PushAsync (new UpcomingAppointmentsPage ());

要导航到的页面被指定为 PushAsync 方法的参数。 在此示例中,将 UpcomingAppointmentsPage 页推送到导航堆栈中,在堆栈中,它成为活动页:

Screenshot of navigation within a tab, on iOS and Android

有关使用 NavigationPage 类执行导航的详细信息,请参阅分层导航

使用模板填充 TabbedPage

通过将数据集合分配给 ItemsSource 属性,并将 DataTemplate 分配给将数据模板化为 Page 对象的 ItemTemplate 属性,可以用页填充 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;
  }
}

在此示例中,每个选项卡都包含一个 ContentPage 对象,该对象使用 ImageLabel 对象来显示该选项卡的数据:

Screenshot of a templated TabbedPage, on iOS and Android

选择另一个选项卡将显示表示该选项卡的 ContentPage 对象。