Android 通過官方Api實現夜間模式


Android夜間模式可以通過手動設置不同的Theme來實現,也有第三方框架可拿來用。在 Android Build 23.0.0后可以使用AppCompatDelegate來實現夜間模式切換。

首先我們需要在style(res/values/style.xml)中生成我們需要主題:

<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.DayNight">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
</resources>

這里的主題繼承了Theme.AppCompat.DayNight,這個主題是一個family,還包含一些額外的主題:
Theme.AppCompat.DayNight.DarkActionBar、Theme.AppCompat.DayNight.NoActionBar等等.都可以使用在夜間模式中.一個夜間,一個白天,顯然需要兩套資源方案,這里設置的只是日間模式(不知道這個表達對不對)下的主題,包括顏色也是日間模式所需要的(/res/values/colors.xml):

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>

    <color name="textColor">#f45d5d</color>
</resources>

接下來需要提供一套夜間模式的資源,可以在/res/下生成一個values-night資源文件夾,
當使用代碼設置夜間模式時,系統會自動引用這個文件夾下的資源.該文件夾下的資源文件名和/res/values/中的文件名保持一致,包括資源Id也需一致,如下:

/res/values-night/style.xml:

<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.DayNight">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

</resources>

/res/values-night/color.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#141212</color>
    <color name="colorPrimaryDark">#423737</color>
    <color name="colorAccent">#2e41ea</color>
    <color name="textColor">#4861ea</color>
</resources>

其他資源文件的設置也是如此,系統會在特定的模式下,自動識別,這里的顏色我是自己配置的,其實更好的方式是使用系統自帶的顏色方案:?android:attr/textColor、?android:attr/textColorPrimary等,避免自己配置的顏色不統一,比如文字顏色和背景色相近,文字就看不清楚了,接下來就是代碼的動態設置。

AppCompatDelegate:

AppCompatDelegate有四種模式可以設置:

MODE_NIGHT_YES:直接指定夜間模式

MODE_NIGHT_NO:直接指定日間模式

MODE_NIGHT_FOLLOW_SYSTEM:根據系統設置決定是否設置夜間模式

MODE_NIGHT_AUTO:根據當前時間自動切換模式

如果要在app啟動的時候就設置夜間模式,可以將代碼寫在Application中:

public class MyApplication extends Application {

    //也可以直接使用代碼塊直接設置
    //static {
     //AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_ NIGHT_YES);
    //}
    @Override
    public void onCreate() {
        super.onCreate();

        //根據app上次退出的狀態來判斷是否需要設置夜間模式,提前在SharedPreference中存了一個是否是夜間模式的boolean值
        boolean isNightMode = NightModeConfig.getInstance().getNightMode(getApplicationContext());
        if (isNightMode) {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
        }else {
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
        }
    }
}

這樣就可以根據用戶的喜好來設置是否啟用夜間模式,需要注意一下幾點:

AppCompatDelegate類中還有一個方法:setLocalNightMode(int mode),這個方法作用在當前組件,Activity中使用 getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES)設置。比如在Application中設置為日間模式,而在當前Activity中調用getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES),該Activity會顯示為夜間模式,覆蓋原來的模式。

AppCompatDelegate.setDefaultNightMode(int mode);只作用於新生成的組件,對原先處於任務棧中的Activity不起作用。如果直接在Activity的onCreate()中調用這句代碼,那當前的Activity中直接生效,不需要再調用recreate(),但我們通常是在監聽器中調用這句代碼,那就需要調用recreate(),否則對當前Activity無效(新生成的Activity還是生效的)。當然可以提前在onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState)中保存好相關屬性值,重建時使用。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM