アプリのNight Modeの切り替え(方法:AppCompatDelegate)

投稿日:  更新日:

アプリを対象としたNight Modeの切り替えは、AppCompatDelegateとUiModeManagerで行う方法がります。

ここでは、AppCompatDelegateを使った方法を説明します。

※Night Modeの切り替えの全体像は「Dark ThemeとNight Modeの関係」を参照

※環境:Android Studio Jellyfish | 2023.3.1
    Kotlin 1.9.0
    Compose Compiler 1.5.1
    androidx.appcompat:appcompat 1.6.1

スポンサーリンク

切り替えの方法

AppCompatDelegate経由で行います。

// YES/NO
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)

// AUTO_TIME(非推奨)
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_TIME)

// AUTO_BATTERY(使用条件あり)
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)

// FOLLOW_SYSTEM
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)

// UNSPECIFIED(指定は不可能)
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_UNSPECIFIED)

AppCompatDelegateはAppCompatActivityがメンバーに持つクラスです。

アプリの下位互換性を維持するために、上位APIの代理を努めるメンバー(関数、メソッドやプロパティ)が定義されています。

public class AppCompatActivity extends FragmentActivity implements AppCompatCallback,
        TaskStackBuilder.SupportParentable, ActionBarDrawerToggle.DelegateProvider {

    private static final String DELEGATE_TAG = "androidx:appcompat";

    private AppCompatDelegate mDelegate;
    private Resources mResources;
	
	...
}

そして、AppCompatActivityは画面をViewシステムで構築する場合にActivityへ継承されます。

ViewシステムJetpack Compose
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
		...
	}
	...
}
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent { /* Composable関数群 */ }
		...
	}
	...
}

つまり、AppCompatDelegate経由で切り替えを行いたければ、Viewシステムを用いる必要があります。

スポンサーリンク

切り替えのタイプ

指定できる切り替えタイプは5つです。

切り替えのタイプ(AppCompatDelegate.XXX)結果
手動MODE_NIGHT_YESスイッチDark OnNight
MODE_NIGHT_NODark OffDay
自動MODE_NIGHT_AUTO_TIME
※非推奨
暦に従う日の入時刻
(22:00)
Day⇒Night
日の出時刻
(06:00)
Night⇒Day
MODE_NIGHT_AUTO_BATTERY
※使用条件あり
バッテリーセーブ連動セーブOnNight
セーブOffDay
その他MODE_NIGHT_FOLLOW_SYSTEMシステムに従う
MODE_NIGHT_UNSPECIFIED
※起動時のみ
切り替えない
※isSystemInDarkTheme()はUiModeManagerに切り替えられた結果を返す
  true:Night Mode、false:Day Mode

MODE_NIGHT_UNSPECIFIEDは初期値で、特定のタイプが指定された後は、元に戻すことが出来ません。ですので、指定は不可能です。

スポンサーリンク

タイプ:YES/NO

手動で行われるOn/Offのスイッチ動作をします。

YESの時刻でDay⇒Nightへ、NOの時刻でNight⇒Dayへ遷移します。

タイプ:YesNoのタイムチャート

スポンサーリンク

タイプ:AUTO_TIME(※非推奨)

現在地の「日の入」/「日の出」時刻に切り替えを行います。

このタイプは非推奨になっています。

    ...
    @Deprecated
    public static final int MODE_NIGHT_AUTO_TIME = 0;
	...
【ドキュメントより】
Automatic switching of dark/light based on the current time is deprecated. Considering using an explicit setting, or MODE_NIGHT_AUTO_BATTERY.
-----
現在時刻をもとにしたdark/lightの自動切換えは非推奨になりました。YES/NOまたはAUTO_BATTERYの使用を考慮してください。

Android端末は常に自身の地図上の位置を把握するように努めています。位置はGPSやネットワーク、電話のアクセスポイントなどから得ます。現在地は最後に確定した地図上の位置です。

現在地の確認は、Google Mapアプリを開き、現在値ボタンを押下すれば分かります。地図の中心が現在地です。

現在地のこよみ

日の入(Sunset)の時刻でDay⇒Nightへ、日の出(Sunrise)の時刻でNight⇒Dayへ遷移します。

スケジュール:SunsetSunriseのタイムチャート

このタイプは、アプリに位置情報のアクセス許可が必要です。

許可がない場合はハードコード(ソースコードに直接記述された時刻)値が用いられます。※ハードコード値:日の入 22:00、日の出 06:00

スポンサーリンク

タイプ:AUTO_BATTERY(※使用条件あり)

バッテリーセーバーに連動して切り替えを行います。

バッテリーセーバーのOnでDay⇒Nightへ、OffでNight⇒Dayへ遷移します。

タイプ:BATTERYのタイプチャート

バッテリーセーバー機能にNight Modeの切り替えを含んでいるデバイスがあります。

例えば、エミュレータ(API34を使用)はバッテリーセーバOnでDark Themeに移行します。

Battery SaverのOn/Off

【ドキュメントより】
Please note: this mode should only be used when running on devices which do not provide a similar device-wide setting.
-----
注意:このモードは同様の機能をシステム全体に提供しないデバイスのみに使用してください。

「同様の機能をシステム全体に提供しないデバイスのみに使用」という条件があります。

スポンサーリンク

タイプ:FOLLOW_SYSTEM

システムを対象としたNight Modeの切り替えに従います。

※システムを対象としたNight Modeの切り替えについては以下をを参照
システムのNight Modeの切り替え(方法:Settingsアプリ、API≧29)
システムのNight Modeの切り替え(方法:UiModeManager、API<29)

スポンサーリンク

setLocalNightModeによる上書き

setDefaultNightModeは、setLocalNightModeによって上書きされます。

setDefaultNightModeの指定setLocalNightModeの指定上書き後のタイプ
XXXYESYES
NONO
AUTO_TIMEAUTO_TIME
BATTERYBATTERY
FOLLOW_SYSEMFOLLOW_SYSEM
UNSPECIFIEDXXX
※「NIGHT_MODE_」は省略
※XXX:タイプ中の一つが入る

setDefaultNightModeの指定を有効にするには、setLocalNightModeの指定をMODE_NIGHT_UNSPECIFIEDにします。

MODE_NIGHT_UNSPECIFIEDは初期値です。

※setLocalNightModeについては「ActivityのNight Modeの切り替え(方法:AppCompatDelegate)」を参照

スポンサーリンク

切り替えの反映

切り替えは直ちに反映されます。

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 -> {}
        }
    }
	...
}

Viewシステムにおいて、Activityの再作成を行わない場合は、LightとDark Themeが切り替わりません。

切り替えは、onConfigureChanged( )内で行われる処理に委ねられます。

スポンサーリンク

付録:エミュレータで現在地の設定

エミュレータで現在地の設定を行う場合は、Extended Controlsパネルを使います。

パネルを開きます。

Extended Controlsパネルを開く

地図を目的の場所へ移動させて、ダブルクリックで場所を決定します。

エミュレータで現在地を設定する

“Set Location”の押下で、現在地として登録されます。

スポンサーリンク

付録:ViewシステムのActivityを作成

Android Studioは「Jetpack Compose」ならびに「Viewシステム」を用いたアプリの開発が可能です。

開発の手法がJecpack Composeに移行した現状においても、Viewシステムが残されています。

ViewシステムのActivityを作成したければ、図のように行います。

ViewシステムのActivity作成Jetpack ComposeのActivity作成
ViewシステムのActivity作成
Jetpack ComposeのActivity作成
スポンサーリンク

関連記事:

「Android Studio Giraffe」の作成するプロジェクトは、Jetpack Composeの利用が推奨されます。 そして、作成されたプロジェクトは、Material Designeに準拠したテーマが指定されます。 ※環境:Android Studio Giraffe | 2022.3.1 Patch 1     Kotlin 1.8.10     Compose Compiler 1.4.3 ...
Android端末は自身の置かれている状況を認識して、ユーザーが使い易いように動作を変える仕組みを持ちます。 uiModeのNight(UI_MODE_NIGHT_YES:夜である)とDay(UI_MODE_NIGHT_NO:昼である) は、その「置かれている状況」の一つです。 NightとDayは古くから定義されているモードです。 API29で追加された機能の「Dark Theme」と結びついて、Night Modeの時はDark Themeにする使い方が定番になってしまいました。 その影響でしょうか... Settingsアプリを見ると、Night Modeの影が薄れて、「Drak 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 ...
システムを対象とした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 ...
システムを対象としたNight Modeの切り替えは、Settingsアプリと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 ...
アプリを対象とした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 ...
Activityを対象としたNight Modeの切り替えは、AppCompatDelegateで行う方法があります。 ここでは、AppCompatDelegateを使った方法を説明します。 ※Night Modeの切り替えの全体像は「Dark ThemeとNight Modeの関係」を参照 ※環境:Android Studio Jellyfish | 2023.3.1     Kotlin 1.9.0     Compose Compiler 1.5.1     androidx.appcompat:appcompat 1.6.1 ...
スポンサーリンク