概述

主要有两种:AppThemeBinding 和ResourceDictionary+Application.Current.Resources.MergedDictionaries+DynamicResource

具体

AppThemeBinding

.NET MAUI 应用可以响应 iOS 13 或更高版本、Android 10 (API 29) 或更高版本、macOS 10.14
或更高版本以及 Windows 10 或更高版本上的系统主题更改。

AppThemeBinding 标记扩展使你能够基于当前系统主题使用资源,如图像或颜色。

AppThemeBinding 标记扩展由 AppThemeBindingExtension 类提供支持,该类定义以下属性:

  • Default,类型为 object,用户所设置的默认使用的资源。
  • Light,类型为 object,用户所设置的在设备使用其浅色主题时要使用的资源。
  • Dark,类型为 object,用户所设置的在设备使用其深色主题时要使用的资源。
  • Value,类型为 object,可返回标记扩展当前使用的资源。
<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>

在 ResourceDictionary 中定义的资源可以在带有 StaticResource 标记扩展的 AppThemeBinding 中使用:

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

此外,在 ResourceDictionary 中定义的资源也可以在带有 DynamicResource 标记扩展的 AppThemeBinding 中使用:

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

.NET MAUI 包含 SetAppThemeColor 和 SetAppTheme 扩展方法,这些方法使 VisualElement 对象能够响应系统主题更改。

SetAppThemeColor 方法允许指定 Color 对象,将基于当前系统主题在目标属性上设置这些对象:

Label label = new Label();
label.SetAppThemeColor(Label.TextColorProperty, Colors.Green, Colors.Red);

在此示例中,当设备使用其浅色主题时,Label 的文本颜色被设置为绿色,当设备使用其深色主题时,文本颜色被设置为红色。

SetAppTheme 方法允许指定 T 对象,将基于当前系统主题在目标属性上设置这些对象:

Image image = new Image();
image.SetAppTheme<FileImageSource>(Image.SourceProperty, "lightlogo.png", "darklogo.png");

可以通过获取 Application.RequestedTheme 属性的值来检测当前系统主题:

AppTheme currentTheme = Application.Current.RequestedTheme;

应用使用的主题可以通过 Application.UserAppTheme 属性(类型为 AppTheme)进行设置,而不管当前运行的是哪个系统主题:

Application.Current.UserAppTheme = AppTheme.Dark;

设备上的系统主题可能会因各种原因而发生更改,具体取决于设备的配置方式。 通过处理 Application.RequestedThemeChanged 事件,可以在系统主题发生更改时通知 .NET MAUI 应用:

Application.Current.RequestedThemeChanged += (s, a) =>
{
    // Respond to the theme change
};

ResourceDictionary+Application.Current.Resources.MergedDictionaries+DynamicResource

基本的原理如下:

  • 定义每个应用主题的ResourceDictionary,每个ResourceDictionary有相同的Key,但值不同。
  • 在根页面App.xaml的资源字典中,引用默认的ResourceDictionary。
  • 使用方式①:直接在页面中,通过DynamicResource扩展标记,引用ResourceDictionary的Key值。
  • 使用方式②:在App.xaml中,定义应用级别的Style,样式值使用DynamicResource扩展标记,引用ResourceDictionary的Key值。页面中,则使用StaticResource扩展标记引用Style。
  • 如需在运行时更改主题,通过后台代码更换ResourceDictionary即可。

一、在Themes文件夹下,创建MAUI的资源字典文件LightTheme.xaml和DarkTheme.xaml
在这里插入图片描述
在这里插入图片描述
二、在根页面App.xaml的资源字典中,引用默认的ResourceDictionary

<Application
    ......>
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Resources/Styles/Colors.xaml" />
                <ResourceDictionary Source="Resources/Styles/Styles.xaml" />
                <!--引用默认主题资源字典LightTheme.xaml-->
                <ResourceDictionary Source="Themes/LightTheme.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

三、在App.xaml中,定义应用级别的Style(非必要)

<Application
    ......>
    <Application.Resources>
        <ResourceDictionary>
            ......
        </ResourceDictionary>
        <!--定义Style,TargetType为Label-->
        <Style x:Key="PrimaryLabelStyle" TargetType="Label">
            <Setter Property="TextColor" Value="{DynamicResource PrimaryTextColor}" />
            <Setter Property="FontSize" Value="25" />
        </Style>
        <Style x:Key="SecondLabelStyle" TargetType="Label">
            <Setter Property="TextColor" Value="{DynamicResource SecondaryTextColor}" />
            <Setter Property="FontSize" Value="30" />
        </Style>
    </Application.Resources>
</Application>

四、在页面中通过DynamicResource扩展标记引用ResourceDictionary的Key值,或通过StaticResource和Style间接引用

<ContentPage
    ......
    BackgroundColor="{DynamicResource PageBackgroundColor}">
    <StackLayout BackgroundColor="{DynamicResource PrimaryColor}">
        <Label Text="直接绑定ResourceDictionary的Key值①" TextColor="{DynamicResource PrimaryTextColor}"/>
        <Label Text="直接绑定ResourceDictionary的Key值②" TextColor="{DynamicResource SecondaryTextColor}"/>
        <Label Text="通过Style间接绑定ResourceDictionary①" Style="{StaticResource PrimaryLabelStyle}"/>
        <Label Text="通过Style间接绑定ResourceDictionary②" Style="{StaticResource PrimaryLabelStyle}"/>
        <Button Text="切换主题" Clicked="Button_Clicked"/>
    </StackLayout>
</ContentPage>

五、通过后台代码切换主题,本案例使用Button的点击事件

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
    }

    private void Button_Clicked(object sender, EventArgs e)
    {
        //获取当前资源字典
        ICollection<ResourceDictionary> mergedDictionaries = Application.Current.Resources.MergedDictionaries;
        //先将当前资源字典清空,再添回暗黑主题DarkTheme
        if (mergedDictionaries != null)
        {
            mergedDictionaries.Clear();
            mergedDictionaries.Add(new DarkTheme());
        }
    }
}

来源

响应系统主题更改
MAUI新生4.6-主题设置LightTheme&DarkTheme

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐