Android實現(xiàn)夜間模式的方法(二)

該文章接上篇 Android實現(xiàn)夜間模式的方法(一)

三.夜間模式的實現(xiàn)方案——單純夜間模式

1.通過切換主題實現(xiàn)

這是通過創(chuàng)建一套夜間模式的主題,然后在設(shè)置時進(jìn)行切換。在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)代碼塊來進(jìn)行初始化全局設(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)的效果如下示例:

效果示例.png

4.通過使用開源框架實現(xiàn)——Android-Skin-Loader

Android-Skin-Loader是一個通過動態(tài)加載本地皮膚包進(jìn)行換膚的皮膚框架
使用方法:

  1. 在Application中進(jìn)行初始化
public class SkinApplication extends Application {
   public void onCreate() {
        super.onCreate();
        // Must call init first 
        SkinManager.getInstance().init(this);
        SkinManager.getInstance().load();
    }
}
  1. 在布局文件中標(biāo)識需要換膚的View
    xmlns:skin="http://schemas.android.com/android/skin"
  2. 繼承BaseActivity或者BaseFragmentActivity作為BaseActivity進(jìn)行開發(fā)
  3. 從.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進(jìn)行夜間模式切換

使用要求
官方包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的頁面,需要使用框架里的封裝控件

MultipleTheme的內(nèi)部代碼1.png
MultipleTheme的內(nèi)部代碼2.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容