アプリを対象としたNight Modeの切り替えは、AppCompatDelegateとUiModeManagerで行う方法がります。
ここでは、UiModeManagerを使った方法を説明します。
※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
切り替えの方法
アプリケーションフレームワークのUiModeManager経由で行います。
val _uiModeMgr = getSystemService(UI_MODE_SERVICE) as UiModeManager
// YES/NO
_uiModeMgr.setApplicationNightMode(UiModeManager.MODE_NIGHT_NO)
_uiModeMgr.setApplicationNightMode(UiModeManager.MODE_NIGHT_YES)
// CUSTOM(無視される)
_uiModeMgr.setApplicationNightMode(UiModeManager.MODE_NIGHT_CUSTOM)
_uiModeMgr.customNightModeStart = LocalTime.parse("19:10:00")
_uiModeMgr.customNightModeEnd = LocalTime.parse("05:30:00")
// AUTO(無視される)
_uiModeMgr.setApplicationNightMode(UiModeManager.MODE_NIGHT_AUTO)
val _uiModeMgr = LocalContext.current.getSystemService(UI_MODE_SERVICE) as UiModeManager
// YES/NO
_uiModeMgr.setApplicationNightMode(UiModeManager.MODE_NIGHT_NO)
_uiModeMgr.setApplicationNightMode(UiModeManager.MODE_NIGHT_YES)
// CUSTOM(無視される)
_uiModeMgr.setApplicationNightMode(UiModeManager.MODE_NIGHT_CUSTOM)
_uiModeMgr.customNightModeStart = LocalTime.parse("19:10:00")
_uiModeMgr.customNightModeEnd = LocalTime.parse("05:30:00")
// AUTO(無視される)
_uiModeMgr.setApplicationNightMode(UiModeManager.MODE_NIGHT_AUTO)
UiModeManager#setApplicationNightMode( )はAPI31で追加されたメソッドです。ですので、API≧31で利用可能です。
切り替えのタイプ
指定できる切り替えのタイプは2つです。
| 切り替えのタイプ(UiModeManager.XXX) | 結果 | |||
|---|---|---|---|---|
| 手動 | MODE_NIGHT_YES | スイッチ | Dark On | Night |
| MODE_NIGHT_NO | Dark Off | Day | ||
| 自動 | MODE_NIGHT_AUTO ※無視される | 暦に従う | 日の入時刻 | Day⇒Night |
| 日の出時刻 | Night⇒Day | |||
| MODE_NIGHT_CUSTOM ※無視される | 指定時刻 | Start時刻 | Day⇒Night | |
| End時刻 | Night⇒Day | |||
| ※isSystemInDarkTheme()はUiModeManagerに切り替えられた結果を返す true:Night Mode、false:Day Mode |
||||
MODE_NIGHT_CUSTOMとMODE_NIGHT_AUTOは指定できますが、無視されます。切り替えは行われません。
タイプ:YES/NO
手動で行われるOn/Offのスイッチ動作をします。
YESの時刻でDay⇒Nightへ、NOの時刻でNight⇒Dayへ遷移します。

切り替えの反映
切り替えは直ちに反映されます。
Settingsアプリで行った場合と異なるので注意してください。。

切り替えは構成の変更を伴って行われます。ですので、Activityは再作成されます。
構成の変更
NightとDay Modeの切り替えが行われると、構成の変更が発生し、Activityが再作成されます。これにより、DarkとLight Themeが切り替わります。
Activityの再作成を行いたくなければ、Manifestファイルへ下記のように追記してください。
Activityの再作成は抑制され、onConfigurationChanged()がコールパックされます。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<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>
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が行われるからです。
関連記事:
