Responder a cambios de tema del sistema
Los dispositivos suelen incluir temas claros y oscuros, que hacen referencia a un amplio conjunto de preferencias de apariencia que se pueden configurar a nivel de sistema operativo. Las aplicaciones deben respetar estos temas del sistema y responder inmediatamente cuando cambia el tema 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.
Las aplicaciones .NET Multi-platform App UI (.NET MAUI) pueden responder a los cambios del tema del sistema mediante el consumo de recursos con la extensión de marcado AppThemeBinding
y los métodos de extensión SetAppThemeColor
y SetAppTheme<T>
.
Nota:
Las aplicaciones .NET MAUI pueden responder a los cambios de tema del sistema en iOS 13 o superior, Android 10 (API 29) o superior, macOS 10.14 o superior y Windows 10 o superior.
En la captura de pantalla siguiente se muestran páginas temáticas para el tema del sistema claro en iOS y el tema del sistema oscuro en Android:
Definir y consumir recursos de tema
Los recursos para temas claros y oscuros se pueden consumir con la extensión de marcado AppThemeBinding
y los métodos de extensión SetAppThemeColor
y SetAppTheme<T>
. Con estos enfoques, los recursos se aplican automáticamente en función del valor del tema del sistema actual. Además, los objetos que consumen estos recursos se actualizan automáticamente si el tema del sistema cambia mientras se ejecuta una aplicación.
AppThemeBinding (extensión de marcado)
La extensión de marcado AppThemeBinding
permite consumir un recurso, como una imagen o un color, en función del tema del sistema actual.
La clase AppThemeBinding
admite la extensión de marcado AppThemeBindingExtension, que define las siguientes propiedades:
Default
, de tipoobject
, que se establece en el recurso que se va a usar de forma predeterminada.Light
, de tipoobject
, que se establece en el recurso que se va a usar cuando el dispositivo usa su tema claro.Dark
, de tipoobject
, que se establece en el recurso que se va a usar cuando el dispositivo usa su tema oscuro.Value
, de tipoobject
, que devuelve el recurso que está usando actualmente la extensión de marcado.
Nota:
El analizador de XAML permite abreviar la clase AppThemeBindingExtension como AppThemeBinding
.
La propiedad Default
es la propiedad de contenido de AppThemeBindingExtension. Por lo tanto, para las expresiones de marcado XAML expresadas con llaves, puedes eliminar la parte Default=
de la expresión siempre que sea el primer argumento.
En el ejemplo siguiente de XAML se muestra cómo usar la extensión de marcado AppThemeBinding
:
<StackLayout>
<Label Text="This text is green in light mode, and red in dark mode."
TextColor="{AppThemeBinding Light=Green, Dark=Red}" />
<Image Source="{AppThemeBinding Light=lightlogo.png, Dark=darklogo.png}" />
</StackLayout>
En este ejemplo, el color de texto del primer Label se establece en verde cuando el dispositivo usa su tema claro y se establece en rojo cuando el dispositivo usa su tema oscuro. Del mismo modo, Image muestra un archivo de imagen diferente en función del tema del sistema actual.
Los recursos definidos en un ResourceDictionary se pueden consumir en un AppThemeBinding
con la extensión de marcado StaticResource
:
<ContentPage ...>
<ContentPage.Resources>
<!-- Light colors -->
<Color x:Key="LightPrimaryColor">WhiteSmoke</Color>
<Color x:Key="LightSecondaryColor">Black</Color>
<!-- Dark colors -->
<Color x:Key="DarkPrimaryColor">Teal</Color>
<Color x:Key="DarkSecondaryColor">White</Color>
<Style x:Key="ButtonStyle"
TargetType="Button">
<Setter Property="BackgroundColor"
Value="{AppThemeBinding Light={StaticResource LightPrimaryColor}, Dark={StaticResource DarkPrimaryColor}}" />
<Setter Property="TextColor"
Value="{AppThemeBinding Light={StaticResource LightSecondaryColor}, Dark={StaticResource DarkSecondaryColor}}" />
</Style>
</ContentPage.Resources>
<Grid BackgroundColor="{AppThemeBinding Light={StaticResource LightPrimaryColor}, Dark={StaticResource DarkPrimaryColor}}">
<Button Text="MORE INFO"
Style="{StaticResource ButtonStyle}" />
</Grid>
</ContentPage>
En este ejemplo, el color de fondo del estilo Grid y del estilo Button cambia en función de si el dispositivo usa su tema claro o su tema oscuro.
Además, los recursos definidos en un ResourceDictionary también se pueden consumir en un AppThemeBinding
con la extensión de marcado DynamicResource
:
<ContentPage ...>
<ContentPage.Resources>
<Color x:Key="Primary">DarkGray</Color>
<Color x:Key="Secondary">HotPink</Color>
<Color x:Key="Tertiary">Yellow</Color>
<Style x:Key="labelStyle" TargetType="Label">
<Setter Property="Padding" Value="5"/>
<Setter Property="TextColor" Value="{AppThemeBinding Light={StaticResource Secondary}, Dark={StaticResource Primary}}" />
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={DynamicResource Primary}, Dark={DynamicResource Secondary}}" />
</Style>
</ContentPage.Resources>
<Label x:Name="myLabel"
Style="{StaticResource labelStyle}"/>
</ContentPage>
Métodos de extensión
.NET MAUI incluye los métodos de extensión SetAppThemeColor
y SetAppTheme<T>
que permiten a los objetos VisualElement responder a los cambios de tema del sistema.
El método SetAppThemeColor
permite especificar objetos Color que se establecerán en una propiedad de destino en función del tema del sistema actual:
Label label = new Label();
label.SetAppThemeColor(Label.TextColorProperty, Colors.Green, Colors.Red);
En este ejemplo, el color de texto de Label se establece en verde cuando el dispositivo usa su tema claro y se establece en rojo cuando el dispositivo usa su tema oscuro.
El método SetAppTheme<T>
permite especificar objetos de tipo T
que se establecerán en una propiedad de destino en función del tema del sistema actual:
Image image = new Image();
image.SetAppTheme<FileImageSource>(Image.SourceProperty, "lightlogo.png", "darklogo.png");
En este ejemplo, Image muestra lightlogo.png
cuando el dispositivo usa su tema claro y darklogo.png
cuando el dispositivo usa su tema oscuro.
Detectar el tema del sistema actual
El tema del sistema actual se puede detectar obteniendo el valor de la propiedad Application.RequestedTheme
:
AppTheme currentTheme = Application.Current.RequestedTheme;
La propiedad RequestedTheme
devuelve un miembro de enumeración AppTheme
. La enumeración AppTheme
define los miembros siguientes:
Unspecified
, que indica que el dispositivo usa un tema no especificado.Light
, que indica que el dispositivo usa su tema claro.Dark
, que indica que el dispositivo usa su tema oscuro.
Establecer el tema de usuario actual
El tema usado por la aplicación se puede establecer con la propiedad Application.UserAppTheme
, que es de tipo AppTheme
, independientemente del tema del sistema que esté operativo actualmente:
Application.Current.UserAppTheme = AppTheme.Dark;
En este ejemplo, se establece que la aplicación utilice el tema definido para el modo de sistema oscuro, independientemente del tema del sistema que esté operativo actualmente.
Nota:
Establece la propiedad UserAppTheme
en AppTheme.Unspecified
para que sea el tema del sistema operativo predeterminado.
Reacción a los cambios de temas
El tema del sistema en un dispositivo puede cambiar por diversos motivos, en función de cómo se configure el dispositivo. Las aplicaciones .NET MAUI se pueden notificar cuando cambia el tema del sistema manejando el evento Application.RequestedThemeChanged
:
Application.Current.RequestedThemeChanged += (s, a) =>
{
// Respond to the theme change
};
El objeto AppThemeChangedEventArgs
que acompaña al evento RequestedThemeChanged
tiene una única propiedad denominada RequestedTheme
, de tipo AppTheme
. Esta propiedad se puede examinar para detectar el tema del sistema solicitado.
Importante
Para responder a los cambios de tema en Android, la clase MainActivity
debe incluir la marca ConfigChanges.UiMode
en el atributo Activity
. Las aplicaciones .NET MAUI creadas con las plantillas de proyecto de Visual Studio incluyen automáticamente esta marca.