Zastosuj motyw w aplikacji

Przeglądaj przykład

Aplikacje .NET Multi-platform App UI (.NET MAUI) mogą dynamicznie reagować na zmiany stylu w czasie wykonywania, używając rozszerzenia znaczników DynamicResource. To rozszerzenie znaczników jest podobne do rozszerzenia znaczników StaticResource, ponieważ oba używają klucza słownika do pobierania wartości z ResourceDictionary. Jednak podczas gdy rozszerzenie znaczników "StaticResource" wykonuje pojedyncze wyszukiwanie w słowniku, rozszerzenie "DynamicResource" utrzymuje połączenie z kluczem słownika. W związku z tym, jeśli wartość skojarzona z kluczem zostanie zamieniona, zmiana zostanie zastosowana do VisualElement. Umożliwia to implementowanie motywów środowiska uruchomieniowego w aplikacjach MAUI platformy .NET.

Proces implementowania motywów środowiska uruchomieniowego w aplikacji .NET MAUI jest następujący:

  1. Zdefiniuj zasoby dla każdego motywu w ResourceDictionary. Aby uzyskać więcej informacji, zobacz Definiowanie motywów.
  2. Ustaw motyw domyślny w pliku App.xaml aplikacji. Aby uzyskać więcej informacji, zobacz Ustaw domyślny motyw.
  3. Korzystanie z zasobów motywu w aplikacji przy użyciu rozszerzenia znaczników DynamicResource. Aby uzyskać więcej informacji, zobacz Korzystanie z zasobów motywu.
  4. Dodaj kod, aby załadować motyw w czasie wykonywania. Aby uzyskać więcej informacji, zobacz "Ładowanie motywu w czasie wykonywania".

Ważne

Użyj rozszerzenia znaczników StaticResource, jeśli aplikacja nie musi dynamicznie zmieniać motywów w czasie wykonywania. Jeśli przewidujesz przełączanie motywów podczas działania aplikacji, użyj rozszerzenia znaczników DynamicResource, które umożliwia aktualizowanie zasobów podczas działania aplikacji.

Poniższy zrzut ekranu przedstawia strony motywowe z aplikacją dla systemu iOS przy użyciu motywu jasnego i aplikacji dla systemu Android przy użyciu motywu ciemnego:

Screenshot of the main page of a themed app.Zrzut ekranu stronę główną aplikacji z motywem.

Uwaga

Zmiana motywu w czasie wykonywania wymaga użycia definicji stylów XAML lub C# i nie jest możliwa przy użyciu arkuszy CSS.

Program .NET MAUI ma również możliwość reagowania na zmiany motywu systemu. Motyw systemowy może ulec zmianie z różnych powodów, w zależności od konfiguracji urządzenia. Obejmuje to jawną zmianę motywu systemowego przez użytkownika, zmianę z powodu pory dnia i zmianę z powodu czynników środowiskowych, takich jak małe światło. Aby uzyskać więcej informacji, zobacz Reagowanie na zmiany motywu systemowego.

Definiowanie motywów

Motyw jest definiowany jako kolekcja zasobów przechowywanych w ResourceDictionary.

W poniższym przykładzie pokazano ResourceDictionary element dla motywu lekkiego o nazwie LightTheme:

<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                    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>

W poniższym przykładzie pokazano przykład dla ResourceDictionary ciemnego motywu o nazwie DarkTheme.

<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                    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>

Każdy ResourceDictionary zawiera Color zasoby, które definiują odpowiednie motywy, przy czym każdy ResourceDictionary używa identycznych wartości kluczy. Aby uzyskać więcej informacji na temat słowników zasobów, zobacz Słowniki zasobów.

Ważne

Dla każdego ResourceDictionary wymagany jest plik kodu zaplecza, który wywołuje metodę InitializeComponent. Jest to konieczne, aby obiekt CLR reprezentujący wybrany motyw można utworzyć w czasie wykonywania.

Ustawianie motywu domyślnego

Aplikacja wymaga motywu domyślnego, aby kontrolki miały wartości dla używanych zasobów. Motyw domyślny można ustawić, scalając ResourceDictionary motywu z ResourceDictionary aplikacji zdefiniowanym w App.xaml:

<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ThemingDemo"
             x:Class="ThemingDemo.App">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <local:LightTheme />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

Aby uzyskać więcej informacji na temat scalania słowników zasobów, zobacz Scalone słowniki zasobów.

Korzystanie z zasobów motywu

Gdy aplikacja chce korzystać z zasobu przechowywanego w ResourceDictionary, który reprezentuje motyw, powinna to zrobić za pomocą rozszerzenia znaczników DynamicResource. Gwarantuje to, że w przypadku wybrania innego motywu w czasie wykonywania zostaną zastosowane wartości z nowego motywu.

W poniższym przykładzie przedstawiono trzy style, które można zastosować do wszystkich Label obiektów w aplikacji:

<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             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>

Te style są definiowane w słowniku zasobów na poziomie aplikacji, dzięki czemu mogą być używane przez wiele stron. Każdy styl korzysta z zasobów motywu dzięki rozszerzeniu znaczników „DynamicResource”.

Te style są następnie używane przez strony:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             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>

Jeśli zasób motywu jest używany bezpośrednio, powinien być stosowany z rozszerzeniem znaczników DynamicResource. Jednak gdy używany jest styl korzystający z rozszerzenia znaczników DynamicResource, powinien być stosowany z rozszerzeniem znaczników StaticResource.

Aby uzyskać więcej informacji na temat stylizowania, zobacz Stylizuj aplikacje za pomocą XAML. Aby uzyskać więcej informacji na temat rozszerzenia znaczników DynamicResource, zobacz Style dynamiczne.

Ładowanie motywu w czasie wykonywania

Gdy w czasie działania aplikacji zostanie wybrany motyw, aplikacja powinna:

  1. Usuń bieżący motyw z właściwości MergedDictionariesResourceDictionary na poziomie aplikacji.
  2. Załaduj wybrany motyw. Jest to osiągane przez dodanie wystąpienia wybranego motywu do właściwości MergedDictionaries na poziomie aplikacji ResourceDictionary.

Każde VisualElement obiekty, które ustawiają właściwości za pomocą DynamicResource rozszerzenia znaczników, będą następnie stosować nowe wartości motywu. Dzieje się tak, ponieważ rozszerzenie `DynamicResource` utrzymuje link do kluczy słownika. Dlatego, gdy wartości skojarzone z kluczami są zastępowane, zmiany są stosowane do obiektów \.

Usuń tylko bieżący słownik kompozycji. Wyczyszczenie MergedDictionaries kolekcji spowoduje również usunięcie innych słowników zasobów na poziomie aplikacji, takich jak Colors.xaml i Styles.xaml w szablonie aplikacji .NET MAUI.

W przykładowej aplikacji motyw jest wybierany przez stronę modalną zawierającą element Picker. Poniższy kod przedstawia metodę OnPickerSelectionChanged, która jest wykonywana po zmianie wybranego motywu:

W poniższym przykładzie pokazano usunięcie bieżącego motywu i załadowanie nowego motywu:

ICollection<ResourceDictionary> mergedDictionaries = Application.Current.Resources.MergedDictionaries;
ResourceDictionary? currentTheme = mergedDictionaries
    .FirstOrDefault(dictionary => dictionary is LightTheme or DarkTheme);

if (currentTheme != null)
{
    mergedDictionaries.Remove(currentTheme);
}

mergedDictionaries.Add(new DarkTheme());