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>。 發生這種情況時,樣式類將以升序排列。 因此,當多個樣式類設置相同的屬性時,位於列表最高位置的樣式類中的屬性將優先

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM