Aplicación de tema a una aplicación
Las aplicaciones .NET Multi-platform App UI (.NET MAUI) pueden responder a cambios de estilo dinámicamente en tiempo de ejecución mediante la extensión de marcado DynamicResource
. Esta extensión de marcado es similar a la extensión de marcado StaticResource
, en que ambas usan una clave de diccionario para capturar un valor de ResourceDictionary. Pero mientras que la extensión de marcado StaticResource
realiza una búsqueda de diccionario única, la extensión de marcado DynamicResource
mantiene un vínculo a la clave de diccionario. Por lo tanto, si se reemplaza el valor asociado con la clave, el cambio se aplica a VisualElement. Esto permite implementar el tema en tiempo de ejecución en aplicaciones .NET MAUI.
El proceso para implementar el creación de temáticas en tiempo de ejecución en una aplicación .NET MAUI es el siguiente:
- Define los recursos para cada tema de un ResourceDictionary. Para más información, consulta Definición de temas.
- Establece un tema predeterminado en el archivo App.xaml de la aplicación. Para más información, consulta Establecer un tema predeterminado.
- Consume recursos de tema en la aplicación mediante la extensión de marcado
DynamicResource
. Para más información, consulta Consumir recursos de tema. - Agrega código para cargar un tema en tiempo de ejecución. Para más información, consulta Cargar un tema en tiempo de ejecución.
Importante
Usa la extensión de marcado StaticResource
si tu aplicación no necesita cambiar temas dinámicamente en tiempo de ejecución. Si prevés cambiar los temas mientras se ejecuta la aplicación, usa la extensión de marcado DynamicResource
, que permite actualizar los recursos en tiempo de ejecución.
En la captura de pantalla siguiente se muestran las páginas temáticas, con la aplicación iOS mediante un tema claro y la aplicación Android mediante un tema oscuro:
Nota:
Cambiar un tema en tiempo de ejecución requiere el uso de definiciones de estilo XAML o C# y no es posible usar CSS.
.NET MAUI también tiene la capacidad de responder a los cambios de temas del sistema. El tema del sistema puede cambiar por diversos motivos, en función de la configuración del dispositivo. Por ejemplo, cuando el usuario cambia explícitamente el tema del sistema y cuando el tema cambia debido a la hora del día y a factores ambientales como luz escasa. Para más información, consulta Responder a los cambios de temas del sistema.
Definición de temas
Un tema se define como una colección de objetos de recursos almacenados en ResourceDictionary.
En el ejemplo siguiente se muestra un ResourceDictionary para un tema claro denominado 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>
En el ejemplo siguiente se muestra un ResourceDictionary para un tema oscuro denominado 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 ResourceDictionary contiene recursos Color que definen sus respectivos temas, con cada ResourceDictionary usando valores de clave idénticos. Para más información sobre los diccionarios de recursos, consulta Diccionarios de recursos.
Importante
Se requiere un archivo de código subyacente para cada ResourceDictionary, que llama al método InitializeComponent
. Esto es necesario para que se pueda crear un objeto CLR que represente el tema elegido en tiempo de ejecución.
Seleccionar un tema predeterminado
Una aplicación requiere un tema predeterminado, de modo que los controles tengan valores para los recursos que consumen. Un tema predeterminado se puede establecer combinando el tema ResourceDictionary en el nivel de aplicación ResourceDictionary que se define en 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 más información sobre los recursos, consulta Diccionarios de recursos combinados.
Consumir recursos de tema
Cuando una aplicación quiere consumir un recurso almacenado en un ResourceDictionary que representa un tema, debe hacerlo con la extensión de marcado DynamicResource
. Esto garantiza que si se selecciona un tema diferente en tiempo de ejecución, se aplicarán los valores del nuevo tema.
En el ejemplo siguiente se muestran tres estilos de que se pueden aplicar a todos los objetos Label de la aplicación:
<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>
Estos estilos se definen en el diccionario de recursos de nivel de aplicación, de modo que se puedan consumir en varias páginas. Cada estilo consume recursos de tema con la extensión de marcado DynamicResource
.
Luego las páginas consumen estos estilos:
<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=" • Cynical but not unfriendly."
Style="{StaticResource SmallLabelStyle}" />
<Label Text=" • Seven varieties of grimaces."
Style="{StaticResource SmallLabelStyle}" />
<Label Text=" • Doesn't laugh at your jokes."
Style="{StaticResource SmallLabelStyle}" />
</StackLayout>
...
</Grid>
</ScrollView>
</ContentPage>
Cuando se consume directamente un recurso de tema, se debe consumir con la extensión de marcado DynamicResource
. Pero cuando se consume un estilo que usa la extensión de marcado DynamicResource
, se debe consumir con la extensión de marcado StaticResource
.
Para obtener más información sobre los estilos, consulta Aplicaciones de estilo con XAML. Para más información sobre la extensión de marcado DynamicResource
, consulta Estilos dinámicos.
Carga de un tema en tiempo de ejecución
Cuando se selecciona un tema en tiempo de ejecución, una aplicación debe:
- Eliminar el tema actual de la aplicación. Esto se logra borrando la propiedad
MergedDictionaries
del nivel de aplicación ResourceDictionary. - Cargar el tema seleccionado. Esto se logra agregando una instancia del tema seleccionado a la propiedad
MergedDictionaries
del nivel de aplicación ResourceDictionary.
Los objetos VisualElement que establezcan propiedades con la extensión de marcado DynamicResource
aplicarán los nuevos valores de tema. Esto ocurre porque la extensión de marcado DynamicResource
mantiene un vínculo a las claves de diccionario. Por lo tanto, cuando se reemplazan los valores asociados a las claves, los cambios se aplican a los objetos VisualElement.
En la aplicación de ejemplo, se selecciona un tema a través de una página modal que contiene una clase Picker. El código siguiente muestra el método OnPickerSelectionChanged
, que se ejecuta cuando cambia el tema seleccionado:
En el ejemplo siguiente se muestra cómo quitar el tema actual y cargar un nuevo tema:
ICollection<ResourceDictionary> mergedDictionaries = Application.Current.Resources.MergedDictionaries;
if (mergedDictionaries != null)
{
mergedDictionaries.Clear();
mergedDictionaries.Add(new DarkTheme());
}