將應用程式主題設定為Xamarin.Forms

Xamarin.Forms 應用程式可以使用標記延伸,在運行 DynamicResource 時間動態響應樣式變更。 這個標記延伸類似於 StaticResource 標記延伸,這兩者都使用字典索引鍵從 ResourceDictionary擷取值。 不過,當標記延伸執行單一字典查閱時 StaticResourceDynamicResource 標記延伸會維護字典索引鍵的連結。 因此,如果已取代與索引鍵相關聯的值,則會將變更套用至 VisualElement。 這可讓運行時間主題在應用程式中實作 Xamarin.Forms 。

在應用程式中實作執行時間主題 Xamarin.Forms 的程式如下:

  1. 定義 中 ResourceDictionary每個主題的資源。
  2. 使用標記延伸,取用 DynamicResource 應用程式中的主題資源。
  3. 在應用程式的 App.xaml 檔案中設定預設主題。
  4. 新增程式代碼以在運行時間載入主題。

重要

StaticResource如果您不需要在運行時間變更應用程式主題,請使用標記延伸。

下列螢幕快照顯示主題頁面,其中 iOS 應用程式使用淺色主題和 Android 應用程式使用深色主題:

iOS 和 Android 上主題應用程式主頁面的螢幕快照iOS 和 Android 上主題應用程式詳細數據頁面的螢幕快照

注意

在運行時間變更主題需要使用 XAML 樣式,而且目前無法使用 CSS。

定義主題

主題定義為儲存在中的 ResourceDictionary資源物件集合。

下列範例顯示 LightTheme 來自範例應用程式的 :

<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    x:Class="ThemingDemo.LightTheme">
    <Color x:Key="PageBackgroundColor">White</Color>
    <Color x:Key="NavigationBarColor">WhiteSmoke</Color>
    <Color x:Key="PrimaryColor">WhiteSmoke</Color>
    <Color x:Key="SecondaryColor">Black</Color>
    <Color x:Key="PrimaryTextColor">Black</Color>
    <Color x:Key="SecondaryTextColor">White</Color>
    <Color x:Key="TertiaryTextColor">Gray</Color>
    <Color x:Key="TransparentColor">Transparent</Color>
</ResourceDictionary>

下列範例顯示 DarkTheme 來自範例應用程式的 :

<ResourceDictionary xmlns="http://xamarin.com/schemas/2014/forms"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    x:Class="ThemingDemo.DarkTheme">
    <Color x:Key="PageBackgroundColor">Black</Color>
    <Color x:Key="NavigationBarColor">Teal</Color>
    <Color x:Key="PrimaryColor">Teal</Color>
    <Color x:Key="SecondaryColor">White</Color>
    <Color x:Key="PrimaryTextColor">White</Color>
    <Color x:Key="SecondaryTextColor">White</Color>
    <Color x:Key="TertiaryTextColor">WhiteSmoke</Color>
    <Color x:Key="TransparentColor">Transparent</Color>
</ResourceDictionary>

每個 ResourceDictionary 都包含 Color 定義其個別主題的資源,且每個資源都 ResourceDictionary 使用相同的索引鍵值。 如需資源字典的詳細資訊,請參閱 資源字典

重要

每個 ResourceDictionary都需要檔案後置程序代碼,其會呼叫 InitializeComponent 方法。 這是必要的,如此一來,就可以在運行時間建立代表所選主題的CLR物件。

設定預設主題

應用程式需要默認主題,讓控件具有其取用資源的值。 您可以將主題ResourceDictionary合併為 App.xaml定義的應用程式層級ResourceDictionary,以設定預設主題:

<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ThemingDemo.App">
    <Application.Resources>
        <ResourceDictionary Source="Themes/LightTheme.xaml" />
    </Application.Resources>
</Application>

如需合併資源字典的詳細資訊,請參閱 合併的資源字典

取用主題資源

當應用程式想要取用儲存在 代表主題之 中的 ResourceDictionary 資源時,應該使用 DynamicResource 標記延伸來執行此動作。 這可確保如果在運行時間選取不同的主題,則會套用新主題中的值。

下列範例顯示可套用至 Label 物件的範例應用程式中的三種樣式:

<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ThemingDemo.App">
    <Application.Resources>

        <Style x:Key="LargeLabelStyle"
               TargetType="Label">
            <Setter Property="TextColor"
                    Value="{DynamicResource SecondaryTextColor}" />
            <Setter Property="FontSize"
                    Value="30" />
        </Style>

        <Style x:Key="MediumLabelStyle"
               TargetType="Label">
            <Setter Property="TextColor"
                    Value="{DynamicResource PrimaryTextColor}" />
            <Setter Property="FontSize"
                    Value="25" />
        </Style>

        <Style x:Key="SmallLabelStyle"
               TargetType="Label">
            <Setter Property="TextColor"
                    Value="{DynamicResource TertiaryTextColor}" />
            <Setter Property="FontSize"
                    Value="15" />
        </Style>

    </Application.Resources>
</Application>

這些樣式定義在應用層級資源字典中,以便可供多個頁面取用。 每個樣式都會使用 DynamicResource 標記延伸的主題資源。

這些樣式接著會由頁面取用:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ThemingDemo"
             x:Class="ThemingDemo.UserSummaryPage"
             Title="User Summary"
             BackgroundColor="{DynamicResource PageBackgroundColor}">
    ...
    <ScrollView>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="200" />
                <RowDefinition Height="120" />
                <RowDefinition Height="70" />
            </Grid.RowDefinitions>
            <Grid BackgroundColor="{DynamicResource PrimaryColor}">
                <Label Text="Face-Palm Monkey"
                       VerticalOptions="Center"
                       Margin="15"
                       Style="{StaticResource MediumLabelStyle}" />
                ...
            </Grid>
            <StackLayout Grid.Row="1"
                         Margin="10">
                <Label Text="This monkey reacts appropriately to ridiculous assertions and actions."
                       Style="{StaticResource SmallLabelStyle}" />
                <Label Text="  &#x2022; Cynical but not unfriendly."
                       Style="{StaticResource SmallLabelStyle}" />
                <Label Text="  &#x2022; Seven varieties of grimaces."
                       Style="{StaticResource SmallLabelStyle}" />
                <Label Text="  &#x2022; Doesn't laugh at your jokes."
                       Style="{StaticResource SmallLabelStyle}" />
            </StackLayout>
            ...
        </Grid>
    </ScrollView>
</ContentPage>

直接取用主題資源時,應該使用標記延伸來取用 DynamicResource 。 不過,當使用標記延伸的DynamicResource樣式使用時,應該使用標記延伸。StaticResource

如需樣式的詳細資訊,請參閱 使用 XAML 樣式設定 Xamarin.Forms 應用程式樣式。 如需標記延伸的詳細資訊 DynamicResource ,請參閱 中的 Xamarin.Forms動態樣式。

在運行時間載入主題

在執行時間選取主題時,應用程式應該:

  1. 從應用程式移除目前的主題。 這可藉由清除 MergedDictionaries 應用層級 ResourceDictionary的屬性來達成。
  2. 載入選取的主題。 這可藉由將所選主題的實例新增至 MergedDictionaries 應用層級 ResourceDictionary的屬性來達成。

任何 VisualElement 使用 DynamicResource 標記延伸設定屬性的對象,都會套用新的主題值。 這是因為 DynamicResource 標記延伸會維護字典索引鍵的連結。 因此,當取代與索引鍵相關聯的值時,這些變更會套用至 VisualElement 物件。

在範例應用程式中,會透過包含 Picker的強制回應頁面選取主題。 下列程式代碼顯示 OnPickerSelectionChanged 方法,這個方法會在選取的主題變更時執行:

void OnPickerSelectionChanged(object sender, EventArgs e)
{
    Picker picker = sender as Picker;
    Theme theme = (Theme)picker.SelectedItem;

    ICollection<ResourceDictionary> mergedDictionaries = Application.Current.Resources.MergedDictionaries;
    if (mergedDictionaries != null)
    {
        mergedDictionaries.Clear();

        switch (theme)
        {
            case Theme.Dark:
                mergedDictionaries.Add(new DarkTheme());
                break;
            case Theme.Light:
            default:
                mergedDictionaries.Add(new LightTheme());
                break;
        }
    }
}