Xamarin.Forms アプリケーションでシステム テーマの変更に対応する

通常、デバイスにはライト テーマとダーク テーマが含まれ、それぞれがオペレーティング システム レベルで設定できる幅広い外観設定を指します。 アプリケーションでは、これらのシステム テーマを考慮し、システム テーマが変更されたときにすぐに対応する必要があります。

システム テーマは、デバイスの構成に応じてさまざまな理由で変更される場合があります。 これには、ユーザーによって明示的に変更されているシステム テーマ、時刻によって変更される、低光量などの環境要因によって変化するシステム テーマが含まれます。

Xamarin.Forms アプリケーションは、AppThemeBinding マークアップ拡張および SetAppThemeColorSetOnAppTheme<T> 拡張メソッドでリソースを使って、システム テーマの変更に対応できます。

Xamarin.Forms でシステム テーマの変更に対応するには、次の要件が満たされている必要があります。

  • Xamarin.Forms 4.6.0.967 以降。
  • iOS 13 以降。
  • Android 10 (API 29) 以降。
  • UWP ビルド 14393 以降。
  • macOS 10.14 以降。

次に示すのは、iOS と Android でライトとダークのシステム テーマが適用されたページのスクリーンショットです。

iOS および Android での、テーマが適用されたアプリのメイン ページのスクリーンショットiOS および Android での、テーマが適用されたアプリの詳細ページのスクリーンショット

テーマ リソースの定義と使用

ライト テーマとダーク テーマのリソースは、AppThemeBinding マークアップ拡張機能、SetAppThemeColor 拡張メソッドと SetOnAppTheme<T> 拡張メソッドと共に使用できます。 これらの方法では、現在のシステム テーマの値に基づいてリソースが自動的に適用されます。 さらに、これらのリソースを使用するオブジェクトは、アプリの実行中にシステム テーマが変更された場合に自動的に更新されます。

AppThemeBinding マークアップ拡張

AppThemeBinding マークアップ拡張を使うと、現在のシステム テーマに基づいて、画像や色などのリソースを使用できます。

<ContentPage ...>
    <StackLayout Margin="20">
        <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>
</ContentPage>

この例では、デバイスがライト テーマを使用している場合、最初の Label のテキストの色が緑色に設定され、デバイスがダーク テーマを使用している場合は赤色に設定されます。 同様に、Image は現在のシステム テーマに基づいて異なるイメージ ファイルを表示します。

さらに、ResourceDictionary で定義されたリソースは、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>    

この例では、デバイスがライト テーマとダーク テーマのどちらを使用しているかに基づいて、GridButton スタイルの背景色が変わります。

AppThemeBinding マークアップ拡張について詳しくは、「AppThemeBinding マークアップ拡張」をご覧ください。

拡張メソッド

Xamarin.Forms に含まれる SetAppThemeColor および SetOnAppTheme<T> 拡張メソッドを使うと、VisualElement オブジェクトでシステム テーマの変更に対応できます。

SetAppThemeColor メソッドを使用すると、現在のシステム テーマに基づいてターゲット プロパティに設定される Color オブジェクトを指定できます。

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

この例では、デバイスがライト テーマを使用している場合、Label のテキストの色は緑色に設定され、デバイスがダーク テーマを使用している場合は赤色に設定されます。

SetOnAppTheme<T> メソッドを使用すると、現在のシステム テーマに基づいてターゲット プロパティに設定される T 型のオブジェクトを指定できます。

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

この例では、Image は、デバイスがライト テーマを使用しているときには lightlogo.png を表示し、デバイスがダーク テーマを使用しているときには darklogo.png を表示します。

現在のシステム テーマを検出する

現在のシステム テーマは、Application.RequestedTheme プロパティの値を取得することで検出できます。

OSAppTheme currentTheme = Application.Current.RequestedTheme;

RequestedTheme プロパティでは、OSAppTheme と呼ばれる列挙型が返されます。 OSAppTheme 列挙型には、次のメンバーが定義されています。

  • Unspecified は、デバイスが未指定のテーマを使用していることを示します。
  • Light は、デバイスがライト テーマを使用していることを示します。
  • Dark は、デバイスがダーク テーマを使用していることを示します。

現在のユーザー テーマを設定する

現在機能するシステム テーマに関係なく、アプリケーションで使われるテーマは、OSAppTheme 型の Application.UserAppTheme プロパティで設定できます。

Application.Current.UserAppTheme = OSAppTheme.Dark;

この例では、現在機能するシステム テーマに関係なく、システム ダーク モード用に定義されているテーマを使うようにアプリケーションを設定しています。

Note

UserAppTheme プロパティを OSAppTheme.Unspecified に設定すると、既定でオペレーティング システム テーマに設定されます。

テーマの変更に対応する

デバイスのシステム テーマは、デバイスの構成に応じて、さまざまな理由で変更される場合があります。 Xamarin.Forms アプリでは、Application.RequestedThemeChanged イベントを処理することで、システム テーマが変更されたときに通知を受け取ることができます。

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

RequestedThemeChanged イベントに付随する AppThemeChangedEventArgs オブジェクトには、OSAppTheme 型の RequestedTheme という名前の単一プロパティがあります。 このプロパティを調べて、要求されたシステム テーマを検出できます。

重要

Android でテーマの変更に対応するには、MainActivity クラスの Activity 属性に ConfigChanges.UiMode フラグを含める必要があります。