Xamarin.Forms 样式简介

可以通过样式来自定义视觉对象元素的外观。 样式针对特定类型进行定义,它包含该类型上可用属性的值。

Xamarin.Forms 应用程序通常包含多个具有相同外观的控件。 例如,应用程序可能有多个具有相同字体选项和布局选项的 Label 实例,如以下 XAML 代码示例所示:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="Styles.NoStylesPage"
    Title="No Styles"
    IconImageSource="xaml.png">
    <ContentPage.Content>
        <StackLayout Padding="0,20,0,0">
            <Label Text="These labels"
                   HorizontalOptions="Center"
                   VerticalOptions="CenterAndExpand"
                   FontSize="Large" />
            <Label Text="are not"
                   HorizontalOptions="Center"
                   VerticalOptions="CenterAndExpand"
                   FontSize="Large" />
            <Label Text="using styles"
                   HorizontalOptions="Center"
                   VerticalOptions="CenterAndExpand"
                   FontSize="Large" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

以下代码示例演示了在 C# 中创建的等效页:

public class NoStylesPageCS : ContentPage
{
    public NoStylesPageCS ()
    {
        Title = "No Styles";
        IconImageSource = "csharp.png";
        Padding = new Thickness (0, 20, 0, 0);

        Content = new StackLayout {
            Children = {
                new Label {
                    Text = "These labels",
                    HorizontalOptions = LayoutOptions.Center,
                    VerticalOptions = LayoutOptions.CenterAndExpand,
                    FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label))
                },
                new Label {
                    Text = "are not",
                    HorizontalOptions = LayoutOptions.Center,
                    VerticalOptions = LayoutOptions.CenterAndExpand,
                    FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label))
                },
                new Label {
                    Text = "using styles",
                    HorizontalOptions = LayoutOptions.Center,
                    VerticalOptions = LayoutOptions.CenterAndExpand,
                    FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label))
                }
            }
        };
    }
}

每个 Label 实例都有相同的属性值,用于控制通过 Label 显示的文本的外观。 这会导致如以下屏幕截图中所示的外观:

Label Appearance without Styles

设置每个单独控件的外观可能是重复性的操作,容易出错。 相反,可以创建用于定义外观的样式,然后将其应用于所需控件。

创建样式

Style 类将属性值的集合分组到一个对象中,然后可以将该对象应用于多个视觉对象元素实例。 这有助于减少重复标记,可以更轻松地更改应用程序的外观。

尽管样式主要是为基于 XAML 的应用程序设计的,但它们也可以在 C# 中创建:

  • 在 XAML 中创建的 Style 实例通常在分配给控件、页面的 Resources 集合或应用程序的 Resources 集合的 ResourceDictionary 中定义。
  • 在 C# 中创建的 Style 实例通常在页面的类中定义,或者在可以进行全局访问的类中定义。

选择在何处定义 Style 会影响其应用范围:

  • 在控件级别定义的 Style 实例只能应用于控件及其子项。
  • 在页面级别定义的 Style 实例只能应用于页面及其子项。
  • 在应用程序级别定义的 Style 实例可以应用于整个应用程序。

每个 Style 实例都包含一个或多个 Setter 对象的集合,其中每个 Setter 都具有 PropertyValueProperty 是应用样式的元素的可绑定属性的名称,而 Value 是应用于属性的值。

每个 Style 实例都可以是显式的或隐式的

  • 显式Style实例是通过指定 TargetTypex:Key 值并将目标元素的 Style 属性设置为 x:Key 引用来定义的。 有关显式样式的详细信息,请参阅显式样式
  • 隐式Style实例是通过仅指定 TargetType 来定义的。 Style 实例随后将自动应用于该类型的所有元素。 请注意,TargetType 的子类不会自动应用 Style。 有关隐式样式的详细信息,请参阅隐式样式

创建 Style 时,始终需要 TargetType 属性。 以下代码示例显示了在 XAML 中创建的显式样式(请注意 x:Key):

<Style x:Key="labelStyle" TargetType="Label">
    <Setter Property="HorizontalOptions" Value="Center" />
    <Setter Property="VerticalOptions" Value="CenterAndExpand" />
    <Setter Property="FontSize" Value="Large" />
</Style>

若要应用 Style,目标对象必须是与 StyleTargetType 属性值匹配的 VisualElement,如以下 XAML 代码示例所示:

<Label Text="Demonstrating an explicit style" Style="{StaticResource labelStyle}" />

视图层次结构中等级较低的样式优先于定义为较高等级的样式。 例如,在应用程序级别设置一个将 Label.TextColor 设置为 RedStyle 时,该操作会被将 Label.TextColor 设置为 Green 的页面级别样式覆盖。 同样,页面级别样式会被控件级别样式覆盖。 此外,如果直接在控件属性上设置 Label.TextColor,则其优先于任何样式。

本部分的文章演示并解释了如何创建和应用显式和隐式样式、如何创建全局样式、样式继承、如何在运行时响应样式更改,以及如何使用 Xamarin.Forms 中包含的内置样式。

注意

什么是 StyleId?

在 Xamarin.Forms 2.2 之前,StyleId 属性用于识别应用程序中的各个元素,以便在 UI 测试和主题引擎(例如 Pixate)中进行识别。 不过,Xamarin.Forms 2.2 引入了 AutomationId 属性,它取代了 StyleId 属性。