zoukankan      html  css  js  c++  java
  • Xamarin.Forms之样式

    使用XAML样式设置Xamarin.Forms应用的样式
    Xamarin.Forms应用程序的样式传统上是通过使用Style类将一组属性值分组到一个对象中来完成的,然后可以将其应用于多个视觉元素实例。 这有助于减少重复标记,并使应用外观更容易更改。

    使用级联样式表样式化Xamarin.Forms应用程序
    Xamarin.Forms支持使用级联样式表(CSS)设置视觉元素的样式。 样式表由规则列表组成,每个规则由一个或多个选择器以及一个声明块组成。

    但是在Xamarin.Forms中,CSS样式表在运行时而不是在编译时进行分析和评估,并且样式表在使用时进行重新分析。更多参考

    以下只介绍通过XAML Styles来设置

    介绍

    样式允许自定义视觉元素的外观。 样式是为特定类型定义的,并包含该类型上可用属性的值。

    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>
    View Code

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

    Create a style

    Style类将属性值的集合分组为一个对象,然后可以将其应用于多个视觉元素实例。这有助于减少重复标记,并使应用程序外观更容易更改。

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

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

    选择在哪里定义样式会影响可以在哪里使用:

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

    注:视图层次结构中较低的样式优先于较高的样式。 例如,在应用程序级别设置将Label.TextColor设置为Red的样式将被将Label.TextColor设置为Green的页面级别样式覆盖。 同样,页面级别样式将被控件级别样式覆盖。 另外,如果直接在控件属性上设置Label.TextColor,则它优先于所有样式。

    每个Style实例都包含一个或多个Setter对象的集合,每个Setter都具有一个Property和一个Value。 “属性”是样式将应用到的元素的可绑定属性的名称,“值”是应用于属性的值

    每个Style实例可以是显式的,也可以是隐式的:

    • 通过指定TargetType和x:Key值,以及将目标元素的Style属性设置为x:Key引用,可以定义一个显式的Style实例。 有关显式样式的更多信息,请参见显式样式
    • 通过仅指定TargetType来定义隐式Style实例。 然后,Style实例将自动应用于该类型的所有元素。 请注意,TargetType的子类不会自动应用样式。 有关隐式样式的更多信息,请参见隐式样式。

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

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.ExplicitStylesPage" Title="Explicit" IconImageSource="xaml.png">
        <ContentPage.Resources>
            <ResourceDictionary>
                <Style x:Key="labelStyle" TargetType="Label">
                    <Setter Property="HorizontalOptions"
                            Value="Center" />
                    <Setter Property="VerticalOptions"
                            Value="CenterAndExpand" />
                    <Setter Property="FontSize" Value="Large" />
                    <Setter Property="TextColor" Value="Red" />
                </Style>
                <Style x:Key="labelGreenStyle" TargetType="Label">
                    ...
                    <Setter Property="TextColor" Value="Green" />
                </Style>
                <Style x:Key="labelBlueStyle" TargetType="Label">
                    ...
                    <Setter Property="TextColor" Value="Blue" />
                </Style>
            </ResourceDictionary>
        </ContentPage.Resources>
    View Code

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

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

    显式样式

    显式样式是通过设置控件的样式属性而有选择地应用于控件的样式。

    要在页面级别声明样式,必须将ResourceDictionary添加到页面,然后可以在ResourceDictionary中包含一个或多个样式声明。 通过为其声明提供x:Key属性来使Style显式化,该属性在ResourceDictionary中为其提供了描述性键。 然后必须通过设置显式样式的“样式”属性将其应用于特定的视觉元素。

    上面的例子就是 定义的显示样式(在页面级别)。

    还可以在控件级别定义样式:

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.ExplicitStylesPage" Title="Explicit" IconImageSource="xaml.png">
        <ContentPage.Content>
            <StackLayout Padding="0,20,0,0">
                <StackLayout.Resources>
                    <ResourceDictionary>
                        <Style x:Key="labelRedStyle" TargetType="Label">
                          ...
                        </Style>
                        ...
                    </ResourceDictionary>
                </StackLayout.Resources>
                <Label Text="These labels" Style="{StaticResource labelRedStyle}" />
                ...
            </StackLayout>
        </ContentPage.Content>
    </ContentPage>
    View Code

    隐式样式

    隐式样式是同一TargetType的所有控件使用的隐式样式,不需要每个控件都引用该样式。

    要在页面级别声明样式,必须将ResourceDictionary添加到页面,然后可以在ResourceDictionary中包含一个或多个样式声明。 通过不指定x:Key属性来使样式隐式化。 然后,该样式将应用于与TargetType完全匹配的视觉元素,但不适用于从TargetType值派生的元素

    以下代码示例显示了XAML在页面的ResourceDictionary中声明的隐式样式,并将其应用于页面的Entry实例:

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:Styles;assembly=Styles" x:Class="Styles.ImplicitStylesPage" Title="Implicit" IconImageSource="xaml.png">
        <ContentPage.Resources>
            <ResourceDictionary>
                <Style TargetType="Entry">
                    <Setter Property="HorizontalOptions" Value="Fill" />
                    <Setter Property="VerticalOptions" Value="CenterAndExpand" />
                    <Setter Property="BackgroundColor" Value="Yellow" />
                    <Setter Property="FontAttributes" Value="Italic" />
                    <Setter Property="TextColor" Value="Blue" />
                </Style>
            </ResourceDictionary>
        </ContentPage.Resources>
        <ContentPage.Content>
            <StackLayout Padding="0,20,0,0">
                <Entry Text="These entries" />
                <Entry Text="are demonstrating" />
                <Entry Text="implicit styles," />
                <Entry Text="and an implicit style override" BackgroundColor="Lime" TextColor="Red" />
                <local:CustomEntry Text="Subclassed Entry is not receiving the style" />
            </StackLayout>
        </ContentPage.Content>
    </ContentPage>
    View Code

    ResourceDictionary定义了一种应用于页面的Entry实例的隐式样式。 样式用于在黄色背景上显示蓝色文本,同时还设置其他外观选项。 样式将添加到页面的ResourceDictionary中,而无需指定x:Key属性。 因此,将样式隐式地应用于所有Entry实例,因为它们与Style的TargetType属性完全匹配。 但是,该样式不适用于CustomEntry实例,它是一个Entry的子类。

    将样式用于派生类型

    Style.ApplyToDerivedTypes属性使样式可以应用于从TargetType属性引用的基本类型派生的控件。 因此,将此属性设置为true可使单个样式定位多种类型,前提是这些类型派生自TargetType属性中指定的基本类型。

    下面的示例显示一个隐式样式,该样式将Button实例的背景色设置为红色:

    全局样式

    通过将样式添加到应用程序的资源字典中,可以使样式全局可用。 这有助于避免在页面或控件之间重复样式。

    默认情况下,从模板创建的所有Xamarin.Forms应用程序都使用App类来实现Application子类。 若要在应用程序级别声明样式,必须在使用XAML的应用程序的ResourceDictionary中,将默认App类替换为XAML App类并在其后添加相关代码。 有关更多信息,请参见Working with the App Class.

    以下代码示例显示了在应用程序级别声明的Style:

    <Application xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.App">
        <Application.Resources>
            <ResourceDictionary>
                <Style x:Key="buttonStyle" TargetType="Button">
                    <Setter Property="HorizontalOptions" Value="Center" />
                    <Setter Property="VerticalOptions" Value="CenterAndExpand" />
                    <Setter Property="BorderColor" Value="Lime" />
                    <Setter Property="BorderRadius" Value="5" />
                    <Setter Property="BorderWidth" Value="5" />
                    <Setter Property="WidthRequest" Value="200" />
                    <Setter Property="TextColor" Value="Teal" />
                </Style>
            </ResourceDictionary>
        </Application.Resources>
    </Application>
    View Code

    样式继承

    样式可以继承其他样式,以减少重复并实现重用。

    通过将Style.BasedOn属性设置为现有Style,可以执行样式继承。 在XAML中,这是通过将BasedOn属性设置为引用以前创建的Style的StaticResource标记扩展来实现的。 在C#中,这是通过将BasedOn属性设置为Style实例来实现的。

    从基本样式继承的样式可以包括新属性的Setter实例,或使用它们从基本样式中覆盖样式。

    此外,从基本样式继承的样式必须以相同的类型为目标,或者从基本样式为目标的类型派生的类型为目标。 例如,如果基本样式针对View实例,则基于基本样式的样式可以针对View实例或从View类派生的类型,例如Label和Button实例。

    以下代码演示了XAML页面中的显式样式继承:

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.StyleInheritancePage" Title="Inheritance" IconImageSource="xaml.png">
        <ContentPage.Resources>
            <ResourceDictionary>
                <Style x:Key="baseStyle" TargetType="View">
                    <Setter Property="HorizontalOptions"
                            Value="Center" />
                    <Setter Property="VerticalOptions"
                            Value="CenterAndExpand" />
                </Style>
                <Style x:Key="labelStyle" TargetType="Label"
                       BasedOn="{StaticResource baseStyle}">
                    ...
                    <Setter Property="TextColor" Value="Teal" />
                </Style>
                <Style x:Key="buttonStyle" TargetType="Button"
                       BasedOn="{StaticResource baseStyle}">
                    <Setter Property="BorderColor" Value="Lime" />
                    ...
                </Style>
            </ResourceDictionary>
        </ContentPage.Resources>
        <ContentPage.Content>
            <StackLayout Padding="0,20,0,0">
                <Label Text="These labels"
                       Style="{StaticResource labelStyle}" />
                ...
                <Button Text="So is the button"
                        Style="{StaticResource buttonStyle}" />
            </StackLayout>
        </ContentPage.Content>
    </ContentPage>
    View Code

    baseStyle以View实例为目标,并设置HorizontalOptions和VerticalOptions属性,baseStyle不能直接在任何控件上设置。 而是,labelStyle和buttonStyle从其继承,设置其他可绑定属性值,然后,通过设置其Style属性,将labelStyle和buttonStyle应用于Label实例和Button实例。

    注:隐式样式可以从显式样式派生,但是显式样式不能从隐式样式派生。

    尊重继承链
    样式只能继承视图层次结构中相同级别或更高级别的样式。 这意味着:

    • 应用程序级资源只能继承其他应用程序级资源。
    • 页面级资源可以从应用程序级资源和其他页面级资源继承。
    • 控制级资源可以从应用程序级资源,页面级资源和其他控制级资源继承。

    动态样式

    样式不响应属性更改,并且在应用程序持续时间内保持不变。 例如,在将样式分配给视觉元素后,如果修改,删除了一个Setter实例或添加了一个新的Setter实例,则更改将不会应用于视觉元素。 但是,应用程序可以使用动态资源在运行时动态响应样式更改

    DynamicResource标记扩展与StaticResource标记扩展类似,两者均使用字典键从ResourceDictionary获取值。 但是,StaticResource执行单个字典查找,DynamicResource会维护指向字典键的链接。 因此,如果替换了与键关联的字典条目,则更改将应用于可视元素,这使得可以在应用程序中进行运行时样式更改。

    下面的代码示例演示XAML页面中的动态样式:

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.DynamicStylesPage" Title="Dynamic" IconImageSource="xaml.png">
        <ContentPage.Resources>
            <ResourceDictionary>
                <Style x:Key="baseStyle" TargetType="View">
                  ...
                </Style>
                <Style x:Key="blueSearchBarStyle"
                       TargetType="SearchBar"
                       BasedOn="{StaticResource baseStyle}">
                  ...
                </Style>
                <Style x:Key="greenSearchBarStyle"
                       TargetType="SearchBar">
                  ...
                </Style>
                ...
            </ResourceDictionary>
        </ContentPage.Resources>
        <ContentPage.Content>
            <StackLayout Padding="0,20,0,0">
                <SearchBar Placeholder="These SearchBar controls"
                           Style="{DynamicResource searchBarStyle}" />
                ...
            </StackLayout>
        </ContentPage.Content>
    </ContentPage>
    View Code

    SearchBar实例使用DynamicResource标记扩展来引用名为searchBarStyle的样式,该样式未在XAML中定义。 但是,由于SearchBar实例的Style属性是使用DynamicResource设置的,因此缺少的字典键不会导致引发异常。

    需要在代码隐藏文件中,构造函数 使用key=searchBarStyle创建一个ResourceDictionary条目,如以下代码示例所示: 

    public partial class DynamicStylesPage : ContentPage
    {
        bool originalStyle = true;
    
        public DynamicStylesPage ()
        {
            InitializeComponent ();
            Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
        }
    
        void OnButtonClicked (object sender, EventArgs e)
        {
            if (originalStyle) {
                Resources ["searchBarStyle"] = Resources ["greenSearchBarStyle"];
                originalStyle = false;
            } else {
                Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
                originalStyle = true;
            }
        }
    }
    View Code

    动态样式继承

    使用Style.BasedOn属性无法实现从动态样式派生样式。 而是,Style类包括BaseResourceKey属性,可以将其设置为字典键,其值可能会动态更改。

    下面的代码示例演示了XAML页面中的动态样式继承:

    见示例

    SearchBar实例使用StaticResource标记扩展来引用名为tealSearchBarStyle的样式。 此样式设置一些其他属性,并使用BaseResourceKey属性引用searchBarStyle。 不需要DynamicResource标记扩展,因为tealSearchBarStyle不会改变,除了它派生的Style之外【BaseResourceKey】。 因此,tealSearchBarStyle维护指向searchBarStyle的链接,并且在基本样式更改时更改。

    在代码隐藏文件中,构造函数使用键searchBarStyle创建一个ResourceDictionary条目,如上一个演示动态样式的示例所示。 执行OnButtonClicked事件处理程序时,searchBarStyle将在blueSearchBarStyle和greenSearchBarStyle之间切换。 这导致以下屏幕快照中显示的外观:

    设备样式

    Xamarin.Forms在Device.Styles类中包含六种动态样式,称为设备样式。

    这些设备样式为:

    所有六个样式只能应用于Label实例。 例如,显示段落正文的Label可以将其Style属性设置为BodyStyle。

    以下代码示例演示了如何在XAML页面中使用设备样式:

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.DeviceStylesPage" Title="Device" IconImageSource="xaml.png">
        <ContentPage.Resources>
            <ResourceDictionary>
                <Style x:Key="myBodyStyle" TargetType="Label"
                  BaseResourceKey="BodyStyle">
                    <Setter Property="TextColor" Value="Accent" />
                </Style>
            </ResourceDictionary>
        </ContentPage.Resources>
        <ContentPage.Content>
            <StackLayout Padding="0,20,0,0">
                <Label Text="Title style"
                  Style="{DynamicResource TitleStyle}" />
                <Label Text="Subtitle text style"
                  Style="{DynamicResource SubtitleStyle}" />
                <Label Text="Body style"
                  Style="{DynamicResource BodyStyle}" />
                <Label Text="Caption style"
                  Style="{DynamicResource CaptionStyle}" />
                <Label Text="List item detail text style"
                  Style="{DynamicResource ListItemDetailTextStyle}" />
                <Label Text="List item text style"
                  Style="{DynamicResource ListItemTextStyle}" />
                <Label Text="No style" />
                <Label Text="My body style"
                  Style="{StaticResource myBodyStyle}" />
            </StackLayout>
        </ContentPage.Content>
    </ContentPage>
    View Code

    设备样式必须使用DynamicResource标记扩展名进行绑定。 通过更改文本大小的辅助功能设置,可以在iOS中看到样式的动态性质。 每个平台上设备样式的外观都不同,如以下屏幕截图所示:

    设备样式也可以通过将BaseResourceKey属性设置为设备样式的键名称来派生。 在上面的代码示例中,myBodyStyle继承自BodyStyle并设置了带重音的文本颜色。 有关动态样式继承的更多信息,请参见动态样式继承。

    可访问性

    设备样式尊重可访问性首选项,因此字体大小将随每个平台上可访问性首选项的改变而变化。 因此,要支持可访问的文本,请确保将设备样式用作应用程序中任何文本样式的基础。

    样式类

    Xamarin.Forms样式类使多种样式可以应用于控件,而无需求助于样式继承。

    创建样式类

    可以通过将Style的Class属性设置为表示类名的字符串来创建样式类。 与使用x:Key属性定义显式样式相比,此方法提供的优点是可以将多个样式类应用于VisualElement。

    注:多种样式可以共享相同的类名,只要它们针对不同的类型。 这使多个名称相同的样式类可以针对不同的类型

    下面的示例显示三个BoxView样式类和一个VisualElement样式类:

    <ContentPage ...>
        <ContentPage.Resources>
            <Style TargetType="BoxView"
                   Class="Separator">
                <Setter Property="BackgroundColor"
                        Value="#CCCCCC" />
                <Setter Property="HeightRequest"
                        Value="1" />
            </Style>
    
            <Style TargetType="BoxView"
                   Class="Rounded">
                <Setter Property="BackgroundColor"
                        Value="#1FAECE" />
                <Setter Property="HorizontalOptions"
                        Value="Start" />
                <Setter Property="CornerRadius"
                        Value="10" />
            </Style>    
    
            <Style TargetType="BoxView"
                   Class="Circle">
                <Setter Property="BackgroundColor"
                        Value="#1FAECE" />
                <Setter Property="WidthRequest"
                        Value="100" />
                <Setter Property="HeightRequest"
                        Value="100" />
                <Setter Property="HorizontalOptions"
                        Value="Start" />
                <Setter Property="CornerRadius"
                        Value="50" />
            </Style>
    
            <Style TargetType="VisualElement"
                   Class="Rotated"
                   ApplyToDerivedTypes="true">
                <Setter Property="Rotation"
                        Value="45" />
            </Style>        
        </ContentPage.Resources>
    </ContentPage>
    View Code

    Separator,Rounded和Circle样式类分别将BoxView属性设置为特定值。

    Rotated样式类具有VisualElement的TargetType,这意味着它只能应用于VisualElement实例。 但是,其ApplyToDerivedTypes属性设置为true,以确保可以将其应用于从VisualElement派生的任何控件,例如BoxView。 

    使用样式类

    可以通过将控件的StyleClass属性(类型为IList <string>)设置为样式类名称列表来使用样式类。 如果控件的类型与样式类的TargetType相匹配,则将应用样式类。

    下面的示例显示三个BoxView实例,每个实例设置为不同的样式类:

    <ContentPage ...>
        <ContentPage.Resources>
            ...
        </ContentPage.Resources>
        <StackLayout Margin="20">
            <BoxView StyleClass="Separator" />       
            <BoxView WidthRequest="100"
                     HeightRequest="100"
                     HorizontalOptions="Center"
                     StyleClass="Rounded, Rotated" />
            <BoxView HorizontalOptions="Center"
                     StyleClass="Circle" />
        </StackLayout>
    </ContentPage>
    View Code

    在此示例中,第一个BoxView的样式设置为行分隔符,而第三个BoxView的样式设置为圆形。 第二个BoxView应用了两个样式类,这些类给其圆角并将其旋转45度:

    注:可以将多个样式类应用于控件,因为StyleClass属性的类型为IList <string>。 发生这种情况时,样式类将以升序排列。 因此,当多个样式类设置相同的属性时,位于列表最高位置的样式类中的属性将优先

  • 相关阅读:
    已知sim3相似变换矩阵,如何求解出R, s, t ,从sim3相似变换矩阵中恢复和获得尺度、旋转、平移
    dynamic_cast用法总结
    为什么不建议用 equals 判断对象相等?
    玩转 Java 动态编译,秀了秀了~!
    如何不改表结构动态扩展字段?
    Java 中 long 是不是原子操作?
    7 个超实用的 MySQL 语句写法,让同事们眼前一亮!
    Spring Boot 集成 Flyway,数据库也能做版本控制,太牛逼了!
    Dubbo 的设计思想,真优秀!
    一个高性能、小而美的序列化工具!
  • 原文地址:https://www.cnblogs.com/peterYong/p/11798243.html
Copyright © 2011-2022 走看看