2017/4/5

Xamarin.Forms 教學系列文(十二.貳)Implicit styles, 一種不用寫 key 的 Style



學習目標
  • Implicit styles
  • Dynamic styles
  • Device styles

每一個 ResourceDictionary 都必須有 key 這個值,若你試著寫一個沒有 key 的 dictionary,一定會出現 NullException。

但是在這一小節,要介紹的是一個不用自己寫 key 的故事… 

Style 內若沒有寫 x:key,系統會由 TargetType 自動產生一組,並找到 TargetType 對應的 Visual Element 套用之。

這就是 Implicit style !!

(以 Button 為例,系統會產生 x:key = Xamarin.Forms.Button,不過你不需要知道)

底下為範例程式碼:

Implicit styles

*OnPlatform 寫法已更改,請參考此篇文章
    <ContentPage.Resources>
        <ResourceDictionary>
            <!--只寫 TargetType-->
            <Style TargetType="Button">
                <Setter Property="HorizontalOptions" Value="Center" />
                <Setter Property="VerticalOptions" Value="CenterAndExpand" />
                <Setter Property="BorderWidth" Value="3" />
                <Setter Property="TextColor" Value="Red" />
                <Setter Property="FontSize" Value="Large" />

                <Setter Property="BackgroundColor">
                    <Setter.Value>
                        <OnPlatform x:TypeArguments="Color" Android="#404040" />
                    </Setter.Value>
                </Setter>

                <Setter Property="BorderColor">
                    <Setter.Value>
                        <OnPlatform x:TypeArguments="Color" Android="White" WinPhone="Black" />
                    </Setter.Value>
                </Setter>
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout>
        <!--Button 自動套用 Style-->
        <Button Text=" Carpe diem " />
        <Button Text=" Sapere aude " />
        <Button Text=" Discere faciendo " />
    </StackLayout>

執行結果:



使用 Implicit style 時,因為 Visual Element 不用指派 Style 的值,所以相當容易混淆到底 Visual Element 有沒有使用 Style...

不然就是要在程式內搜尋有沒有這個 Visual Element 的 Implicit style

所以把握一個原則Style 越接近要修改的 Visual Element 越好維護,尤其是 Implicit style。

除此之外,由於 Implicit style 沒有 key,所以不支援其他 Style 用 BasedOn 來繼承。


底下程式碼展示了如何在各個層級下寫 Style --

共三層 (Application, ContentPage, StackLayout),可以注意 Visual Element 會套用最接近的 Style:
<Application xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             x:Class="StyleHierarchy.App">

    <!--Application.Resources-->
    <Application.Resources>
        <ResourceDictionary>
            <Style x:Key="visualStyle" TargetType="VisualElement">
                <Setter Property="BackgroundColor" Value="Pink" />
            </Style>
        </ResourceDictionary>
    </Application.Resources>
</Application>

DemoPage.xaml
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             x:Class="StyleHierarchy.StyleHierarchyPage" 
             Style="{StaticResource visualStyle}">

    <!--ContentPage.Resources-->
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style x:Key="baseStyle" TargetType="View" BasedOn="{StaticResource visualStyle}">
                <Setter Property="HorizontalOptions" Value="Center" />
                <Setter Property="VerticalOptions" Value="CenterAndExpand" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout>

        <!--StackLayout.Resources-->
        <StackLayout.Resources>
            <ResourceDictionary>
                <Style TargetType="Label" BasedOn="{StaticResource baseStyle}">
                    <Setter Property="TextColor" Value="Black" />
                    <Setter Property="FontSize" Value="Large" />
                </Style>

                <Style TargetType="Button" BasedOn="{StaticResource baseStyle}">
                    <Setter Property="TextColor" Value="Blue" />
                    <Setter Property="FontSize" Value="Large" />
                    <Setter Property="BorderColor" Value="Blue" />
                    <Setter Property="BorderWidth" Value="2" />
                </Style>
            </ResourceDictionary>
        </StackLayout.Resources>

        <Button Text=" Carpe diem " />
        <Label Text ="A bit of text" />
        <Button Text=" Sapere aude " />
        <Label Text ="Another bit of text" />
        <Button Text=" Discere faciendo " />

    </StackLayout>
</ContentPage>

執行結果:


Dynamic styles

此章節講解如何在 .cs 檔內去動態修改 Style。

直接看程式碼好了… 書上的廢話有點多…

XAML 內有三個  Style,要注意 Button 引用的 buttonStyle 不存在於目前 XAML ,所以初始 Button 沒有套用至任何 Style,

要等到 Button 按下時才由 .C# 去設定 Style,注意這裡用的是 DynamicResource:
<!--此 code 與原文書相比刪減了 button2 和 button3-->
    
<ContentPage.Resources>
    <ResourceDictionary>
        
        <Style x:Key="baseButtonStyle" TargetType="Button">
            <Setter Property="FontSize" Value="Large" />
        </Style>

        <Style x:Key="buttonStyle1" TargetType="Button" BasedOn="{StaticResource baseButtonStyle}">
            <Setter Property="HorizontalOptions" Value="Center" />
            <Setter Property="VerticalOptions" Value="CenterAndExpand" />
            <Setter Property="TextColor" Value="Red" />
        </Style>

    </ResourceDictionary>
</ContentPage.Resources>

<StackLayout>
    <Button Text=" Switch to Style #1 " 
            Style="{DynamicResource buttonStyle}" 
            Clicked="OnButton1Clicked" />
</StackLayout>




.cs 的部分,在 OnClicked 事件內去指派 Style 給 buttonStyle
public partial class DynamicStylesPage : ContentPage
{
    public DynamicStylesPage()
    {
        InitializeComponent();
    }

    void OnButton1Clicked(object sender, EventArgs args)
    {
        Resources["buttonStyle"] = Resources["buttonStyle1"];
    }
    
}

按下後就會更改 Style 了喔!


關於繼承,動態 Style 不能用上一小節學的 BaseOn 來繼承,若有 Style 要繼承自動態 Style 要改用 BaseResourceKey 這個屬性。
<Style x:Key="newButtonStyle" TargetType="Button" BaseResourceKey="buttonStyle">


Device styles

Xamarin.Forms 內建六個手機本身的 Dynamic Style 可以繼承:
  • BodyStyle
  • TitleStyle 
  • SubtitleStyle
  • CaptionStyle 
  • ListItemTextStyle
  • ListItemDetailTextStyle 

因為是 Dynamic Style,使用時要搭配 DyanmicResource:
 <Label Text="Body Style" Style="{DynamicResource BodyStyle}" />

要繼承的話也請記得用 BaseResourceKey ...

.cs 寫法如下:
Device.Styles.SubtitleStyleKey



沒有留言:

張貼留言