Configurar o tema de uma aplicação

Procurar exemplo. Procurar o exemplo

As aplicações .NET Multi-platform App UI (.NET MAUI) podem responder dinamicamente a alterações de estilo em tempo de execução, utilizando a DynamicResource extensão de marcação. Esta extensão de marcação é semelhante à StaticResource extensão de marcação, pois ambas usam uma chave de dicionário para obter um valor de um ResourceDictionary. No entanto, enquanto a StaticResource extensão de marcação realiza uma única consulta de dicionário, a DynamicResource extensão de marcação mantém um link para a chave do dicionário. Portanto, se o valor associado à chave for substituído, a alteração é aplicada ao VisualElement. Isto permite a implementação de tematização em tempo de execução nas aplicações MAUI .NET.

O processo para implementar a tematização em tempo de execução numa aplicação .NET MAUI é o seguinte:

  1. Defina os recursos para cada tema num ResourceDictionary. Para mais informações, veja Definir temas.
  2. Defina um tema predefinido no ficheiro App.xaml da aplicação. Para mais informações, veja Definir um tema predefinido.
  3. Consuma os recursos do tema na aplicação, usando a extensão de marcação DynamicResource. Para mais informações, consulte os recursos do tema Consume.
  4. Adicionar código para carregar um tema em tempo de execução. Para mais informações, consulte Carregar um tema em tempo de execução.

Importante

Usa a StaticResource extensão de marcação se a tua aplicação não precisar de mudar de tema dinamicamente em tempo de execução. Se antecipar mudar de temas enquanto a aplicação estiver em execução, use a DynamicResource extensão de marcação, que permite atualizar recursos durante a execução.

A captura de ecrã seguinte mostra páginas temáticas, com a aplicação iOS a usar um tema claro e a app Android a usar um tema escuro:

Captura de ecrã da página principal de uma aplicação temática.

Observação

Mudar um tema em tempo de execução requer o uso de definições ao estilo XAML ou C#, e não é possível usando CSS.

O .NET MAUI também tem a capacidade de responder a alterações de temas do sistema. O tema do sistema pode mudar por várias razões, dependendo da configuração do dispositivo. Isto inclui o tema do sistema ser explicitamente alterado pelo utilizador, alterado devido à hora do dia e alterado devido a fatores ambientais como pouca luz. Para mais informações, consulte Responder às alterações do tema do sistema.

Definir temas

Um tema é definido como uma coleção de objetos de recurso armazenados num ResourceDictionary.

O exemplo seguinte mostra um ResourceDictionary para um tema claro chamado 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>

O exemplo seguinte mostra um ResourceDictionary para um tema escuro chamado 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>

Cada um ResourceDictionary contém Color recursos que definem os seus respetivos temas, com cada um ResourceDictionary a usar valores-chave idênticos. Para mais informações sobre dicionários de recursos, consulte Dicionários de Recursos.

Importante

É necessário um ficheiro de bastidor de código para cada ResourceDictionary, que chama o método InitializeComponent. Isto é necessário para que um objeto CLR que represente o tema escolhido possa ser criado em tempo de execução.

Definir um tema padrão

Uma aplicação exige um tema padrão, para que os controlos tenham valores para os recursos que consomem. Um tema padrão pode ser definido combinando o tema `ResourceDictionary` no `ResourceDictionary` da aplicação definido em `App.xaml`.

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

Para mais informações sobre a fusão de dicionários de recursos, consulte Dicionários de recursos mesclados.

Consumir recursos temáticos

Quando uma aplicação quer consumir um recurso armazenado ResourceDictionary num elemento que representa um tema, deve fazê-lo com a extensão de marcação DynamicResource. Isto garante que, se for selecionado um tema diferente em tempo de execução, os valores do novo tema serão aplicados.

O exemplo seguinte mostra três estilos que podem ser aplicados a todos os objetos na aplicação:

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

Estes estilos são definidos no dicionário de recursos ao nível da aplicação, para que possam ser consumidos por várias páginas. Cada estilo consome recursos do tema com a extensão de marcação DynamicResource.

Estes estilos são então absorvidos pelas páginas:

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

Quando um recurso de tema é consumido diretamente, deve ser utilizado através da extensão de marcação DynamicResource. No entanto, quando um estilo que utiliza a extensão de marcação DynamicResource é consumido, deve ser consumido com a extensão de marcação StaticResource.

Para mais informações sobre estilo, consulte Aplicações de estilo usando XAML. Para mais informações sobre a DynamicResource extensão de marcação, veja Estilos Dinâmicos.

Carregar um tema em tempo de execução

Quando um tema é selecionado em tempo de execução, uma aplicação deve:

  1. Remova o tema atual da aplicação. Isto é conseguido limpando a MergedDictionaries propriedade do nível ResourceDictionaryda aplicação .
  2. Carregue o tema selecionado. Isto é conseguido adicionando uma instância do tema selecionado à MergedDictionaries propriedade do nível ResourceDictionaryda aplicação .

Quaisquer objetos que definam VisualElement propriedades com a DynamicResource extensão de marcação aplicam então os novos valores do tema. Isto acontece porque a DynamicResource extensão de marcação mantém uma ligação às chaves do dicionário. Portanto, quando os valores associados às chaves são substituídos, as alterações são aplicadas aos VisualElement objetos.

Na aplicação de exemplo, um tema é selecionado através de uma página modal que contém um Picker. O código seguinte mostra o OnPickerSelectionChanged método, que é executado quando o tema selecionado muda:

O exemplo seguinte mostra a remoção do tema atual e o carregamento de um novo tema:

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