响应系统主题更改

Browse sample. 浏览示例

设备通常包含浅色主题和深色主题,每个主题都是指可以在操作系统级别设置的一组广泛的外观首选项。 应用应该遵循这些系统主题,并在系统主题发生变化时立即做出响应。

系统主题可能会因各种原因而更改,具体取决于设备配置。 这包括用户以显式方式更改的系统主题,它会基于一天中的时间而更改,并且会根据环境因素(如低亮度)而更改。

.NET Multi-platform App UI (.NET MAUI) 应用可以通过使用 AppThemeBinding 标记扩展以及 SetAppThemeColorSetAppTheme<T> 扩展方法来使用资源,从而响应系统主题更改。

注意

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

下面的屏幕截图展示了已设置主题的页面,分别是 iOS 上的浅色系统主题和 Android 上的深色系统主题:

Screenshot of the main page of a themed app.

定义和使用主题资源

可以借助 AppThemeBinding 标记扩展以及 SetAppThemeColorSetAppTheme<T> 扩展方法来使用浅色和深色主题的资源。 通过这些方法,可以根据当前系统主题的值自动应用资源。 此外,如果在应用运行时系统主题发生更改,则使用这些资源的对象会自动更新。

AppThemeBinding 标记扩展

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

AppThemeBindingExtension 类支持 AppThemeBinding 标记扩展,并定义以下属性:

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

注意

XAML 分析程序允许将 AppThemeBindingExtension 类缩写为 AppBindingTheme

Default 属性是 AppThemeBindingExtension 的内容属性。 因此,对于用大括号表示的 XAML 标记表达式,只要 Default= 部分是第一个参数,就可以将其删除。

下面的 XAML 示例展示了如何使用 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>

在此示例中,当设备使用其浅色主题时,第一个 Label 的文本颜色被设置为绿色;当设备使用其深色主题时,该文本颜色被设置为红色。 同样,Image 根据当前系统主题显示不同的图像文件。

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>    

在此示例中,GridButton 样式的背景颜色将根据设备使用的是浅色主题还是深色主题而相应变化。

此外,在 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 包含 SetAppThemeColorSetAppTheme<T> 扩展方法,这些方法使 VisualElement 对象能够响应系统主题更改。

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

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

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

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

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

在此示例中,当设备使用其浅色主题时,Image 显示 lightlogo.png,而当设备使用其深色主题时,则会显示 darklogo.png

检测当前系统主题

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

AppTheme currentTheme = Application.Current.RequestedTheme;

RequestedTheme 属性将返回 AppTheme 枚举成员。 AppTheme 枚举定义下列成员:

  • Unspecified 指示设备正在使用未指定的主题。
  • Light 指示设备正在使用其浅色主题。
  • Dark 指示设备正在使用其深色主题。

设置当前用户主题

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

Application.Current.UserAppTheme = AppTheme.Dark;

在此示例中,应用被设置为使用为系统深色模式定义的主题,而不管当前运行的是哪个系统主题。

注意

UserAppTheme 属性设置为 AppTheme.Unspecified 以默认使用操作系统主题。

对主题更改作出响应

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

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

RequestedThemeChanged 事件随附的 AppThemeChangedEventArgs 对象包含一个名为 RequestedTheme 的属性,类型为 AppTheme。 可以检查此属性以检测请求的系统主题。

重要

要在 Android 上响应主题更改,MainActivity 类必须在 Activity 特性中包含 ConfigChanges.UiMode 标志。 使用 Visual Studio 项目模板创建的 .NET MAUI 应用会自动包含此标志。