システムを対象としたNight Modeの切り替えは、SettingsアプリとUiModeManagerで行う方法がります。
ここでは、Settingsアプリを使った方法を説明します。
※Night Modeの切り替えの全体像は「Dark ThemeとNight Modeの関係」を参照
※環境:Android Studio Jellyfish | 2023.3.1
Kotlin 1.9.0
Compose Compiler 1.5.1
androidx.compose.foundation:foundation 1.5.0
Emulator 35.1.4-11672324
目次 [非表示]
切り替えの方法
SettingsアプリのDisplayページから行います。
スイッチをOn/Offして手動で切り替える方法と、スケジュール(切り替えの時刻)を定義して自動で切り替える方法が準備されています。
ここで行われる切り替えはシステム全体(端末全体)に有効です。つまり、全アプリのモードが切り替わります。
スケジュールの種類
定義できるスケジュールは4つです。
切り替えのスケジュール | 結果 | ||
---|---|---|---|
手動 (API≧29) | Dark On | Night | |
Dark Off | Day | ||
自動 (API≧30) | None(手動) | Dark On | Night |
Dark Off | Day | ||
Turns on at custom time | Start時刻 | Day⇒Night | |
End時刻 | Night⇒Day | ||
Thrns on from sunset to sunrise | 日の入時刻 | Day⇒Night | |
日の出時刻 | Night⇒Day | ||
Turns on at bedtime (API≧33) | 就寝時刻 | Day⇒Night | |
起床時刻 | Night⇒Day | ||
アプリ内で固定 | NightまたはDay | ||
※isSystemInDarkTheme()はスケジュールによって切り替えられた結果を返す true:Night Mode、false:Day Mode |
スケジュール:None
スケジュールはありません。単なるOn/Offのスイッチ動作をします。
Onの時刻でDay⇒Nightへ、Offの時刻でNight⇒Dayへ遷移します。
切り替えはOn/Offで即座に反映されます。
スケジュール:Turns on at custon time
指定時刻(StartとEnd)に切り替えを行います。
Startの時刻でDay⇒Nightへ、Endの時刻でNight⇒Dayへ遷移します。
切り替えはStart/Endで即座に反映されません。(後述)
スケジュール:Turns on from suset to sunrise
現在地の「日の入」/「日の出」時刻に切り替えを行います。
Android端末は常に自身の地図上の位置を把握するように努めています。位置はGPSやネットワーク、電話のアクセスポイントなどから得ます。現在地は最後に確定した地図上の位置です。
現在地の確認は、Google Mapアプリを開き、現在値ボタンを押下すれば分かります。地図の中心が現在地です。
日の入(Sunset)の時刻でDay⇒Nightへ、日の出(Sunrise)の時刻でNight⇒Dayへ遷移します。
切り替えは「日の入」/「日の出」で即座に反映されません。(後述)
スケジュール:Turns on at bedtime
就寝/起床時刻に切り替えを行います。
Digital WellbeingツールはAPI29(Android 10)で追加されました。その中のBedtime Modeは就寝時の端末の振る舞いを変える機能です。
就寝時間はスケジュールや充電の有無で決まります。
就寝の時刻でDay⇒Nightへ、起床の時刻でNight⇒Dayへ遷移します。
切り替えは就寝/起床で即座に反映されません。(後述)
就寝時刻になった時に、ステータスバーへ通知は届きます。
しかし、グレースケール(画面のカスタマイズ機能)になりません。また、ダークテーマ(Night Mode)にもなりません。
切り替えの反映
切り替えは、スクリーンがOffからOnになる時に反映されます。
例えば、「Powerボタン押下してスリープになり、再びPowerボタン押下してウェイクアップした時」などです。
ですので、アプリの使用中に、突発的に切り替わることはありません。
切り替えは構成の変更に伴って行われます。ですので、Activityは再作成されます。
構成の変更
NightとDay Modeの切り替えが行われると、構成の変更が発生し、Activityが再作成されます。これにより、DarkとLight Themeが切り替わります。
Activityの再作成を行いたくなければ、Manifestファイルへ下記のように追記してください。
Activityの再作成は抑制され、onConfigurationChanged()がコールパックされます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <? xml version = "1.0" encoding = "utf-8" ?> < application ...> < activity android:name = ".MainActivity" android:exported = "true" android:label = "@string/app_name" android:theme = "@style/Theme.DarkMode" android:configChanges = "uiMode" > < intent-filter > < action android:name = "android.intent.action.MAIN" /> < category android:name = "android.intent.category.LAUNCHER" /> </ intent-filter > </ activity > </ application > </ manifest > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class MainActivity : ComponentActivity() { ... override fun onConfigurationChanged(newConfig: Configuration) { super .onConfigurationChanged(newConfig) val _nightMode = newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK when(_nightMode) { Configuration.UI_MODE_NIGHT_NO -> { /* 処理 */ } // Night Mode Configuration.UI_MODE_NIGHT_YES -> { /* 処理 */ } // Day Mode Configuration.UI_MODE_NIGHT_UNDEFINED -> { /* 処理 */ } else -> {} } } ... } |
Jetpack Composeにおいて、Activityを再作成しない場合でも、LightとDark Themeが切り替わります。
これは、isSystemInDarkTheme()の出力が変わることで、Composable関数(UI要素)の状態が変化し、再Composeが行われるからです。
付録:Settingsアプリを開く
プログラム中からSettinsアプリの関連ページを開くには、下記のようにします。
Displayページ
1 2 3 4 5 6 7 8 9 10 11 12 13 | /** * Activity Action: Show settings to allow configuration of display. * <p> * In some cases, a matching Activity may not exist, so ensure you * safeguard against this. * <p> * Input: Nothing. * <p> * Output: Nothing. */ @SdkConstant (SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS" ; |
1 2 3 4 5 | fun openSettingsDisplay() { startActivity( Intent(Settings.ACTION_DISPLAY_SETTINGS) ) } |
Dark themeページ
「Settings.ACTION_DARK_THEME_SETTINGS」は隠しパラメータ(@hide)です。一般のユーザーは、このパラメータを使えません。
しかし、パラメータは単なる文字列なので、文字列を直書きすれば開きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /** * Activity Action: Show settings to allow configuration of Dark theme. * <p> * In some cases, a matching Activity may not exist, so ensure you * safeguard against this. * <p> * Input: Nothing. * <p> * Output: Nothing. * * @hide */ @SdkConstant (SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_DARK_THEME_SETTINGS = "android.settings.DARK_THEME_SETTINGS" ; |
1 2 3 4 5 6 | @RequiresApi (Build.VERSION_CODES.R) fun openSettingsDarkTheme() { startActivity( Intent( "android.settings.DARK_THEME_SETTINGS" ) // 文字列を直書き ) } |
付録:エミュレータで現在地の設定
エミュレータで現在地の設定を行う場合は、Extended Controlsパネルを使います。
パネルを開きます。
地図を目的の場所へ移動させて、ダブルクリックで場所を決定します。
“Set Location”の押下で、現在地として登録されます。
関連記事: