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)中保存好相關屬性值,重建時使用。