アプリを対象とした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が行われるからです。
関連記事: