Android实现夜间模式的方法(二)

该文章接上篇 Android实现夜间模式的方法(一)

三.夜间模式的实现方案——单纯夜间模式

1.通过切换主题实现

这是通过创建一套夜间模式的主题,然后在设置时进行切换。在Activity中有一个方法叫setTheme(),可以设置Activity的Theme,当然Application类中也有相同的方法,也可以在Application中设置当前应用的Theme。

首先在attrs.xml中,为需要随theme变化的内容设置自定义属性

<resources>
    <attr name="textColor" format="color|reference" />
    <attr name="mainBackground" format="color|reference" />
</resources>

然后定义自己的夜间模式的风格,示例如下:

<!-- 夜间 -->
    <style name="ThemeNight" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="mainBackground">#000000</item>
        <item name="textColor">#ffffff</item>
    </style>

接下来只要在布局文件中使用对应的值,通过?attr/属性名的方法就可以实现根据风格设置不同的属性的目的。

这种方法是是Android官方推荐的方式,较为简单常用但这种方式有一些不足,规模较大的应用,需要随theme变化的属性会很多,都需要逐一定义。

2.通过修改资源id映射方式实现

这种方法的思路是通过id获取资源时,先将其转换为夜间模式对应id,再通过Resources来获取对应的资源。

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来一一对应起来

private static void buildResourceMap() {
    sResourceMap = new SparseIntArray();
    sResourceMap.put(R.drawable.common_background, R.drawable.common_background_night);
    // ...
}

3.通过使用系统提供的夜间模式主题实现

在Support Library 23.2.0添加了一条新的变化 AppCompat 现在有个新的主题:Theme.AppCompat.DayNight. 这个主题可以根据系统时间切换 Theme.AppCompat(暗色) 和 Theme.AppCompat.Light(亮色) 两种主题。这将会对应用的用户特别有用,特别是阅读类应用。需要注意的是,这个特性只支持 API v14 及以上的 Android 设备,在 API v14 以下的设备则会默认使用亮色的主题。而且activity必须继承要AppCompatActivity。

首先得先在你的 style.xml 文件里,让主题继承 DayNight 主题,例如:

<style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar">

然后在 Application 添加一个静态代码块来进行初始化全局设置:

static {
    AppCompatDelegate.setDefaultNightMode(
        AppCompatDelegate.MODE_NIGHT_AUTO); 
}
然后使用自定义资源,只需要在 res 目录下创建对应的 values-night 文件夹并创建对应的 themes.xml 文件,重新定义夜间模式的主题风格,例如:
res/values-night/colors.xml
<color name="colorPrimary">#201D45</color>
<color name="colorPrimaryDark">#201D45</color>

同理其他资源你只需要在文件的末尾添加 -night 系统就会自动加载对应的文件了。
实现的效果如下示例:

效果示例.png

4.通过使用开源框架实现——Android-Skin-Loader

Android-Skin-Loader是一个通过动态加载本地皮肤包进行换肤的皮肤框架
使用方法:

  1. 在Application中进行初始化
public class SkinApplication extends Application {
   public void onCreate() {
        super.onCreate();
        // Must call init first 
        SkinManager.getInstance().init(this);
        SkinManager.getInstance().load();
    }
}
  1. 在布局文件中标识需要换肤的View
    xmlns:skin="http://schemas.android.com/android/skin"
  2. 继承BaseActivity或者BaseFragmentActivity作为BaseActivity进行开发
  3. 从.skin文件中设置皮肤
SkinManager.getInstance().load(skin.getAbsolutePath(),
                new ILoaderListener() {
//重写该类下的方法
});

皮肤包(后缀名为.skin)的本质是一个apk文件,该apk文件不包含代码,只包含资源文件

在皮肤包工程中(示例工程为skin/BlackFantacy)添加需要换肤的同名的资源文件,直接编译生成apk文件,再更改后缀名为.skin即可(防止用户点击安装)

使用gradle的同学,buildandroid-skin-loader-skin工程后即可在skin-package目录下取皮肤包(修改脚本中def skinName = "BlackFantacy.skin"换成自己想要的皮肤名)

Load包下的两个类
SkinInflaterFactory: 搜集需要的换肤的控件,并创建相应的换肤控件,并把需要换肤的空间及其相应支持的换肤属性存储起来。

SkinManager: 其内部通过反射调用AssetManager.addAssetPath()把外部的皮肤资源加载到AssetManager中,并通过该AssetManager创建相应的Resource。当执行换肤操作的时候,就可以设置需要换肤View的相关属性为Resource中相应的资源。

5.通过使用开源框架实现——NightModel

NightModel是个方便切换夜间模式的库,利用官方夜间模式,同时不用重启Activity
使用方法
1.在appication中初始化
2.只需要在需要刷新的activity中调用attach、detach方法。其它activity不需要调用此方法
3.切换时调用appleyDayModel\appleyNightModel进行夜间模式切换

使用要求
官方包support appcompat 23.2.0 或以上版本
activity 需要继承自 AppCompatActivity
应用按照官方的夜间模式实现

6.通过使用开源框架实现——MultipleTheme

MultipleTheme是一个支持无缝换肤/夜间模式的Android框架,配合theme和换肤控件框架可以做到无缝切换换肤(无需重启应用和当前页面)。需要在换肤/切换夜间模式的界面只需要使用框架里的自封装控件,其他界面的控件使用原生android控件即可。

第一步:在项目的attr.xml声明自定义属性(各种模式都会用到的属性)
第二步:在项目的style.xml指定各种模式主题下的自定义属性值
第三步:在页面布局文件里使用自定义属性值
第四步:在基类的onCreate方法里添加切换主题模式的逻辑代码
第五步:调用工具类方法切换主题模式
第六步:针对切换主题模式时需要立即更新页面ui的页面,需要使用框架里的封装控件

MultipleTheme的内部代码1.png
MultipleTheme的内部代码2.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容