ダークテーマ

Android Q では、Android システムの UI とデバイス上で実行されるアプリの両方に適用可能な新しいダークテーマを使用できます。

ダークテーマにはさまざまなメリットがあります。

  • (デバイスの画面テクノロジーによっては)電力使用量を大幅に削減できます。
  • 低視力のユーザーや明るい光に敏感なユーザーが画面を見やすくなります。
  • すべてのユーザーが薄暗い環境でもデバイスを簡単に操作できます。

Android Q では、次の 3 種類の方法でダークテーマを有効にすることができます。

  • 新しいシステム設定([設定] > [ディスプレイ] > [テーマ])でダークテーマを有効にすることができます。
  • 新しい [クイック設定] タイルの通知トレイ(有効になっている場合)でテーマをすばやく切り替えることができます。
  • Pixel デバイスのバッテリー セーバー モードでダークテーマを同時に有効にすることもできます。他の OEM は、この動作をサポートしている場合とサポートしていない場合があります。

アプリでのダークテーマのサポート

ダークテーマをサポートするためには、DayNight テーマから継承するようにアプリのテーマ(通常、res/values/styles.xml にあります)を設定する必要があります。

<style name="AppTheme" parent="Theme.AppCompat.DayNight">
    

MaterialComponents のダークテーマを使用することもできます。

<style name="AppTheme" parent="Theme.MaterialComponents.DayNight">
    

これにより、システムによって制御される夜間モードフラグにアプリのメインテーマが関連付けられ、アプリでデフォルトのダークテーマを使用できるようになります(有効になっている場合)。

テーマとスタイル

テーマとスタイルに関しては、ライトテーマで使用する目的でハードコードされた色やアイコンを避ける必要があります。代わりに、テーマ属性(推奨)または夜間に適したリソースを使用してください。

非常に重要なテーマ属性として次の 2 つがあります。

  • ?android:attr/textColorPrimary: テーマ全般で使用するテキストの色。ライトテーマでは黒に近い色、ダークテーマでは白に近い色になります。この属性には無効な状態が含まれています。
  • ?attr/colorControlNormal: テーマ全般で使用するアイコンの色。この属性には無効な状態が含まれています。

マテリアル デザイン コンポーネントカラーテーマ設定システム?attr/colorSurface?attr/colorOnSurface などのテーマ属性)で適切な色を簡単に決められるため、このコンポーネントを使用することをおすすめします。もちろん、これらの属性はテーマ内でカスタマイズできます。

アプリ内でのテーマの変更

アプリの実行中にユーザーがアプリのテーマを変更できるようにすることをおすすめします。その場合、アプリ内でユーザーがテーマを選択できるようにします。

Android 9 以前が実行されているデバイスでの推奨テーマ オプションは次のとおりです。

  • ライト
  • ダーク
  • バッテリー セーバーが自動で設定(推奨デフォルト オプション)

Android Q では推奨オプションが異なり、ユーザーがシステムのデフォルトをオーバーライドできるようにします。

  • ライト
  • ダーク
  • システムのデフォルト(推奨デフォルト オプション)

ユーザーが [ライト] を選択しても、バッテリー セーバーはその設定を変更しません。

各オプションは、AppCompat.DayNight モードのいずれかに直接マッピングされます。

テーマを切り替えるには、AppCompatDelegate.setDefaultNightMode() を呼び出します。

フォースダーク

デベロッパーは Android Q のフォースダーク機能を使用して、ダークテーマをすばやく実装することができます。前述のように DayNight テーマを明示的に設定する必要はありません。

フォースダークでは、ライトテーマに設定されているアプリの各ビューを分析し、画面に描画される前にダークテーマを自動的に適用します。一部のデベロッパーは、フォースダークとネイティブの実装を組み合わせて使用することで、ダークテーマの実装に必要な時間を短縮しています。

アプリでフォースダークを有効にするには、アプリのテーマで android:forceDarkAllowed="true" のように設定する必要があります。この属性は、ライトテーマ(Theme.Material.Light など)をサポートしているすべてのシステムと AndroidX で設定します。フォースダークを使用する場合は、アプリを徹底的にテストし、必要に応じてビューを除外する必要があります。

アプリでダークテーマ(Theme.Material など)を使用すると、フォースダークが適用されなくなります。同様に、アプリのテーマを DayNight テーマから継承すると、テーマの自動切り替えにより、フォースダークが適用されなくなります。

ビューでのフォースダークの無効化

android:forceDarkAllowed レイアウト属性または setForceDarkAllowed() を使用すると、特定のビューでフォースダークを制御できます。

おすすめの方法

通知とウィジェット

デバイスに表示はするが直接管理はしない UI サーフェスに関しては、使用するすべてのビューにホストアプリのテーマを反映することが重要です。通知とランチャー ウィジェットはその好例です。

通知

システムが提供する通知テンプレート(MessagingStyle など)を使用します。つまり、システムが責任を持って、適切なビュースタイルが適用されるようにする必要があります。

ウィジェットとカスタム通知ビュー

ランチャー ウィジェットを使用する場合や、アプリでカスタムの通知コンテンツ ビューを使用する場合、ライトテーマとダークテーマの両方でコンテンツをテストすることが重要です。

陥りやすい落とし穴:

  • 背景色は常に明るいと仮定する
  • テキストの色をハードコードする
  • ハードコードされた背景色を設定し、さらにデフォルトのテキストの色を使用する
  • 静的な色の描画可能なアイコンを使用する

上記のいずれの場合も、ハードコードされた色ではなく、適切なテーマ属性を使用してください。

起動画面

アプリにカスタムの起動画面がある場合、選択したテーマが反映されるようにするために変更が必要になることがあります。

ハードコードされた色はすべて削除します(たとえば、背景色の指定が白になっていることがあります)。代わりに、?android:attr/colorBackground テーマ属性を使用します。

ダークテーマに設定された android:windowBackground ドローアブルは Android Q でのみ使用できます。

設定の変更

アプリのテーマが(システム設定または AppCompat のいずれかで)変更されると、uiMode の設定変更がトリガーされます。つまり、アクティビティが自動的に再作成されます。

場合によっては、アプリで設定変更に対処することもできます。たとえば、動画の再生中は設定変更を後で行うほうがよいかもしれません。

アプリでダークテーマ自体の実装を処理するには、各アクティビティで uiMode の設定変更に対処できることを宣言します。

<activity
        android:name=".MyActivity"
        android:configChanges="uiMode" />
    

アクティビティで設定変更に対処することを宣言すると、テーマが変更されたときにアクティビティの onConfigurationChanged() メソッドが呼び出されます。

現在のテーマを確認するには、アプリで次のようなコードを実行します。

Kotlin

val currentNightMode = configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
    when (currentNightMode) {
        Configuration.UI_MODE_NIGHT_NO -> {} // Night mode is not active, we're using the light theme
        Configuration.UI_MODE_NIGHT_YES -> {} // Night mode is active, we're using dark theme
    }

Java

int currentNightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK;
    switch (currentNightMode) {
        case Configuration.UI_MODE_NIGHT_NO:
            // Night mode is not active, we're using the light theme
            break;
        case Configuration.UI_MODE_NIGHT_YES:
            // Night mode is active, we're using dark theme
            break;
    }