ダークモードを実装する

Compose を試す
Jetpack Compose は、Android に推奨される UI ツールキットです。Compose でテーマ設定を使用する方法について学習します。

図 1. ダークモード。

ダークテーマは、Android 10(API レベル 29)以上で利用可能です。機能 次のような利点があります

  • デバイスの状況に応じて消費電力を大幅に削減します 対応しています。
  • 視力の低いユーザーや明るい光に敏感なユーザーにとって、画面の見やすさが向上します。
  • 暗い場所でのデバイスの使いやすさが向上します。

ダークモードは、Android システム UI とデバイスで実行されるアプリに適用されます。

Android 10 以降でダークモードを有効にするには、次の 3 つの方法があります。

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

WebView コンポーネントを使用してウェブベースのコンテンツにダークテーマを適用する手順については、WebView のウェブ コンテンツをダークテーマ化するをご覧ください。

アプリでダークモードをサポートする

ダークモードをサポートするには、アプリのテーマを設定します。通常は res/values/styles.xml - DayNight テーマから継承します。

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

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

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

これは、システムが制御する夜間モードのフラグと、 有効になっている場合、アプリにデフォルトのダークモードが設定されます。

テーマとスタイル

ライトテーマで使用する目的でハードコードされた色やアイコンは使用しないでください。使用 夜間に有効なリソースを使用します。

ダークモードでは、次の 2 つのテーマ属性が特に重要です。

  • ?android:attr/textColorPrimary: 汎用のテキストの色。内容 ライトモードでは黒に近い色、ダークモードでは白に近い色です。この属性には「無効」状態もあります。
  • ?attr/colorControlNormal: 汎用のアイコンの色。この属性には「無効」状態もあります。

マテリアル デザインの コンポーネントカラーテーマ設定のため) 変更することもできます 属性の ?attr/colorSurface および ?attr/colorOnSurface により、 最適な色に変更できますこれらの属性はテーマ内でカスタマイズできます。

アプリ内でテーマを変更する

アプリの実行中にユーザーがアプリのテーマを変更できるようにすることができます。推奨されるオプションは次のとおりです。

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

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

テーマを切り替えるには、次の操作を行います。

  • API レベル 31 以降では、次のコマンドを使用します。 UiModeManager#setApplicationNightMode アプリが動作しているテーマをシステムに通知します。これにより、スプラッシュ画面でテーマを照合できます。

  • API レベル 30 以下では、次のコマンドを使用します。 AppCompatDelegate.setDefaultNightMode() テーマを切り替えます。

フォースダーク

Android 10 では、フォースダークというデベロッパー向けの機能が提供されています。 DayNight テーマを明示的に設定せずにダークモードをすばやく実装できます。

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

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

アプリがダークテーマ(Theme.Material など)を使用している場合、フォースダークは適用されません。同様に、アプリのテーマが DayNight テーマを継承している場合、テーマは自動的に切り替えられるので、フォースダークは適用されません。

ビューで強制ダークを無効にする

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

ウェブ コンテンツ

ウェブベースのコンテンツでダークテーマを使用する方法については、WebView のウェブ コンテンツにダークテーマを適用するをご覧ください。ダークモードの例として 適用される場合は、WebView のデモを GitHub をタップします。

おすすめの方法

以下のセクションでは、ダークテーマの実装に関するおすすめの方法を紹介します。

通知とウィジェット

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

通知

システムが提供する通知テンプレート(MessagingStyle など)を使用します。つまり、適切なビュースタイルの適用はシステムが行います。

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

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

陥りやすい落とし穴には次のようなものがあります。

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

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

起動画面

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

プログラムで設定された背景色など、ハードコードされた色をすべて削除します。 白。代わりに ?android:attr/colorBackground テーマ属性を使用してください。

構成の変更

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

場合によっては、アプリで設定変更に対処することもできます。たとえば、動画の再生中に構成の変更を遅延させる場合などです。

アプリは、それぞれが次のように宣言することで、ダークモードの実装を処理できます。 ActivityuiMode の構成変更を処理できます。

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

Activity が構成の変更を処理することを宣言すると、 onConfigurationChanged() メソッドはテーマの変更時に呼び出されます。

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

KotlinJava
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.
}
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;
}