該文章接上篇 Android實現(xiàn)夜間模式的方法(一)
三.夜間模式的實現(xiàn)方案——單純夜間模式
1.通過切換主題實現(xiàn)
這是通過創(chuàng)建一套夜間模式的主題掺炭,然后在設(shè)置時進行切換驹尼。在Activity中有一個方法叫setTheme(),可以設(shè)置Activity的Theme夕吻,當(dāng)然Application類中也有相同的方法乌逐,也可以在Application中設(shè)置當(dāng)前應(yīng)用的Theme擎椰。
首先在attrs.xml中逻住,為需要隨theme變化的內(nèi)容設(shè)置自定義屬性
<resources>
<attr name="textColor" format="color|reference" />
<attr name="mainBackground" format="color|reference" />
</resources>
然后定義自己的夜間模式的風(fēng)格钟哥,示例如下:
<!-- 夜間 -->
<style name="ThemeNight" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="mainBackground">#000000</item>
<item name="textColor">#ffffff</item>
</style>
接下來只要在布局文件中使用對應(yīng)的值迎献,通過?attr/屬性名的方法就可以實現(xiàn)根據(jù)風(fēng)格設(shè)置不同的屬性的目的瞎访。
這種方法是是Android官方推薦的方式,較為簡單常用但這種方式有一些不足吁恍,規(guī)模較大的應(yīng)用扒秸,需要隨theme變化的屬性會很多,都需要逐一定義冀瓦。
2.通過修改資源id映射方式實現(xiàn)
這種方法的思路是通過id獲取資源時伴奥,先將其轉(zhuǎn)換為夜間模式對應(yīng)id,再通過Resources來獲取對應(yīng)的資源翼闽。
public static Drawable getDrawable(Context context, int id) {
return context.getResources().getDrawable(getResId(id));
}
public static int getResId(int defaultResId) {
if (!isNightMode()) {
return defaultResId;
}
if (sResourceMap == null) {
buildResourceMap();
}
int themedResId = sResourceMap.get(defaultResId);
return themedResId == 0 ? defaultResId : themedResId;
}
可以通過HashMap將白天模式的resId和夜間模式的resId來一一對應(yīng)起來
private static void buildResourceMap() {
sResourceMap = new SparseIntArray();
sResourceMap.put(R.drawable.common_background, R.drawable.common_background_night);
// ...
}
3.通過使用系統(tǒng)提供的夜間模式主題實現(xiàn)
在Support Library 23.2.0添加了一條新的變化 AppCompat 現(xiàn)在有個新的主題:Theme.AppCompat.DayNight. 這個主題可以根據(jù)系統(tǒng)時間切換 Theme.AppCompat(暗色) 和 Theme.AppCompat.Light(亮色) 兩種主題拾徙。這將會對應(yīng)用的用戶特別有用,特別是閱讀類應(yīng)用感局。需要注意的是尼啡,這個特性只支持 API v14 及以上的 Android 設(shè)備,在 API v14 以下的設(shè)備則會默認(rèn)使用亮色的主題询微。而且activity必須繼承要AppCompatActivity崖瞭。
首先得先在你的 style.xml 文件里,讓主題繼承 DayNight 主題撑毛,例如:
<style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar">
然后在 Application 添加一個靜態(tài)代碼塊來進行初始化全局設(shè)置:
static {
AppCompatDelegate.setDefaultNightMode(
AppCompatDelegate.MODE_NIGHT_AUTO);
}
然后使用自定義資源书聚,只需要在 res 目錄下創(chuàng)建對應(yīng)的 values-night 文件夾并創(chuàng)建對應(yīng)的 themes.xml 文件,重新定義夜間模式的主題風(fēng)格,例如:
res/values-night/colors.xml
<color name="colorPrimary">#201D45</color>
<color name="colorPrimaryDark">#201D45</color>
同理其他資源你只需要在文件的末尾添加 -night 系統(tǒng)就會自動加載對應(yīng)的文件了雌续。
實現(xiàn)的效果如下示例:
4.通過使用開源框架實現(xiàn)——Android-Skin-Loader
Android-Skin-Loader是一個通過動態(tài)加載本地皮膚包進行換膚的皮膚框架
使用方法:
- 在Application中進行初始化
public class SkinApplication extends Application {
public void onCreate() {
super.onCreate();
// Must call init first
SkinManager.getInstance().init(this);
SkinManager.getInstance().load();
}
}
- 在布局文件中標(biāo)識需要換膚的View
xmlns:skin="http://schemas.android.com/android/skin"
- 繼承BaseActivity或者BaseFragmentActivity作為BaseActivity進行開發(fā)
- 從.skin文件中設(shè)置皮膚
SkinManager.getInstance().load(skin.getAbsolutePath(),
new ILoaderListener() {
//重寫該類下的方法
});
皮膚包(后綴名為.skin)的本質(zhì)是一個apk文件斩个,該apk文件不包含代碼,只包含資源文件
在皮膚包工程中(示例工程為skin/BlackFantacy)添加需要換膚的同名的資源文件驯杜,直接編譯生成apk文件萨驶,再更改后綴名為.skin即可(防止用戶點擊安裝)
使用gradle的同學(xué),buildandroid-skin-loader-skin工程后即可在skin-package目錄下取皮膚包(修改腳本中def skinName = "BlackFantacy.skin"換成自己想要的皮膚名)
Load包下的兩個類
SkinInflaterFactory: 搜集需要的換膚的控件艇肴,并創(chuàng)建相應(yīng)的換膚控件腔呜,并把需要換膚的空間及其相應(yīng)支持的換膚屬性存儲起來。
SkinManager: 其內(nèi)部通過反射調(diào)用AssetManager.addAssetPath()把外部的皮膚資源加載到AssetManager中再悼,并通過該AssetManager創(chuàng)建相應(yīng)的Resource核畴。當(dāng)執(zhí)行換膚操作的時候,就可以設(shè)置需要換膚View的相關(guān)屬性為Resource中相應(yīng)的資源冲九。
5.通過使用開源框架實現(xiàn)——NightModel
NightModel是個方便切換夜間模式的庫谤草,利用官方夜間模式,同時不用重啟Activity
使用方法
1.在appication中初始化
2.只需要在需要刷新的activity中調(diào)用attach莺奸、detach方法丑孩。其它activity不需要調(diào)用此方法
3.切換時調(diào)用appleyDayModel\appleyNightModel進行夜間模式切換
使用要求
官方包support appcompat 23.2.0 或以上版本
activity 需要繼承自 AppCompatActivity
應(yīng)用按照官方的夜間模式實現(xiàn)
6.通過使用開源框架實現(xiàn)——MultipleTheme
MultipleTheme是一個支持無縫換膚/夜間模式的Android框架,配合theme和換膚控件框架可以做到無縫切換換膚(無需重啟應(yīng)用和當(dāng)前頁面)灭贷。需要在換膚/切換夜間模式的界面只需要使用框架里的自封裝控件温学,其他界面的控件使用原生android控件即可。
第一步:在項目的attr.xml聲明自定義屬性(各種模式都會用到的屬性)
第二步:在項目的style.xml指定各種模式主題下的自定義屬性值
第三步:在頁面布局文件里使用自定義屬性值
第四步:在基類的onCreate方法里添加切換主題模式的邏輯代碼
第五步:調(diào)用工具類方法切換主題模式
第六步:針對切換主題模式時需要立即更新頁面ui的頁面甚疟,需要使用框架里的封裝控件